Fix "Operation not permitted" on Linux, Even as Root

Quick fix

If even sudo cannot change or delete a file, check for the immutable attribute:

lsattr /path/to/file
sudo chattr -i /path/to/file

An i (immutable) or a (append-only) in the lsattr output blocks every change, including by root. If there is no attribute, the cause is the file system, the sticky bit, or a missing capability: find your case below.

What the error means

"Operation not permitted" is the text for the kernel error EPERM. It is not the same as "Permission denied" (EACCES). Permission denied means the read/write/execute bits or a security module refused access; using sudo often fixes it. Operation not permitted means the operation itself is forbidden for this process in this context, so being root frequently makes no difference. Typical forms:

rm: cannot remove 'resolv.conf': Operation not permitted
chmod: changing permissions of '/media/usb/run.sh': Operation not permitted
chown: changing ownership of 'data': Operation not permitted
dmesg: read kernel buffer failed: Operation not permitted
mount: /mnt: permission denied.
unshare: write failed /proc/self/uid_map: Operation not permitted

Use the command that failed to pick the right cause below.

Cause 1: the file is immutable or append-only (chattr)

Linux file systems (ext4, XFS, Btrfs) support attributes beyond normal permissions. +i makes a file immutable: nobody, not even root, can modify, rename, delete or link to it. +a allows only appending. Administrators set these to protect files such as /etc/resolv.conf from being overwritten; malware sometimes sets them to protect itself.

lsattr /etc/resolv.conf
lsattr -d /some/directory

Example output:

----i---------e------- /etc/resolv.conf
Find out why it was set first

An immutable flag is usually deliberate. Removing it from /etc/resolv.conf may let NetworkManager or a VPN client overwrite your DNS settings; removing it from an unknown file in /tmp, /usr/bin or a cron directory may be a sign of compromise worth investigating before you delete anything.

sudo chattr -i /etc/resolv.conf
sudo chattr -a /var/log/app.log
# make it immutable again later
sudo chattr +i /etc/resolv.conf

If an immutable directory blocks you, check it with lsattr -d: files inside cannot be created or removed while the directory itself is +i.

Cause 2: deleting another user's file in /tmp (sticky bit)

/tmp and /var/tmp have the sticky bit (drwxrwxrwt): anyone can create files, but only the owner of a file (or of the directory, or root) can delete or rename it. Removing someone else's file as a normal user gives "Operation not permitted". Use sudo if it really is yours to clean up, or leave it for systemd-tmpfiles to expire. The file permissions guide explains the sticky bit.

Cause 3: chmod or chown on a file system without Unix permissions

FAT32, exFAT and NTFS (via ntfs3 or ntfs-3g without special options) do not store Linux owners and modes. Every file appears with the owner and mode chosen at mount time, and chmod/chown fail or silently do nothing. Set ownership through mount options instead:

findmnt -no FSTYPE,OPTIONS /media/usb
sudo umount /media/usb
sudo mount -o uid=$(id -u),gid=$(id -g),umask=022 /dev/sdb1 /media/usb

For permanent mounts use the same options in /etc/fstab; the NTFS and exFAT mounting guide has working fstab lines. NFS shares behave similarly: with the default root_squash, root on the client is mapped to nobody and chown fails with this error. Change ownership on the server instead.

A related but different error is "Read-only file system", which means the whole mount is read-only.

Cause 4: chown as a normal user

Only root (more precisely, a process with CAP_CHOWN) can give a file to another user. As a normal user, chown otheruser file always fails with "Operation not permitted", even on your own files. Use sudo chown. You can change the group to one of your own groups with chgrp. See the chmod and chown cheat sheet for the syntax.

Cause 5: a missing capability inside a container or service

Root inside a Docker or Podman container is not full root: the runtime drops most capabilities and applies a seccomp filter. Operations such as mount, changing network settings, setting the clock, loading modules or using ptrace fail with EPERM. Grant only what is needed:

# network configuration inside the container
docker run --cap-add=NET_ADMIN myimage
# debugging with strace/gdb
docker run --cap-add=SYS_PTRACE myimage
# a specific device instead of everything
docker run --device /dev/ttyUSB0 myimage
Avoid --privileged

--privileged disables most isolation and gives the container access to every host device. Use it only to confirm the diagnosis, then replace it with the specific --cap-add or --device.

systemd services can hit the same wall when their unit uses sandboxing options such as CapabilityBoundingSet=, SystemCallFilter=, NoNewPrivileges= or PrivateDevices=. Check with systemctl cat myapp.service and relax only the option that blocks the operation, via sudo systemctl edit myapp.service.

Cause 6: kernel restrictions on unprivileged users

  • dmesg: most distros set kernel.dmesg_restrict=1, so reading the kernel log needs root. Run sudo dmesg or journalctl -k (as a member of adm/systemd-journal).
  • User namespaces on Ubuntu: Ubuntu 24.04 and later restrict unprivileged user namespaces through AppArmor (kernel.apparmor_restrict_unprivileged_userns=1). Sandboxed apps, AppImages and tools like unshare or bwrap without an AppArmor profile fail with uid_map or namespace errors. The right fix is an AppArmor profile for that application; turning the restriction off system-wide weakens a security hardening, so do it only temporarily for testing.
  • ping as a normal user: needs either CAP_NET_RAW on the binary or your group in net.ipv4.ping_group_range. Reinstalling the iputils/iputils-ping package restores the default.
  • ptrace/gdb -p: blocked by kernel.yama.ptrace_scope. Attach with sudo or start the program under the debugger.

Distro-specific notes

  • Ubuntu, Debian, Mint: chattr/lsattr are in e2fsprogs, installed by default. Ubuntu's AppArmor namespace restriction (above) is the most common EPERM source for third-party desktop apps.
  • Fedora: SELinux denials normally appear as "Permission denied", not EPERM; check sudo ausearch -m avc -ts recent if unsure. Never disable SELinux permanently to fix this.
  • Arch: install e2fsprogs if lsattr is missing on a Btrfs-only system.
  • openSUSE: Leap 16 and Tumbleweed use SELinux by default; older Leap releases use AppArmor. The same ausearch check applies on SELinux systems.

How to prevent it

  • Document any chattr +i you set (a comment in the file, or your config management), so the next admin does not fight it.
  • Mount removable FAT/exFAT/NTFS drives with the right uid/gid from the start.
  • Run containers with the minimum capabilities and add them one by one when something fails.
  • When an error says "Permission denied" instead, the fix is usually permissions or ownership: see bash: Permission denied.

Frequently asked questions

What is the difference between Permission denied and Operation not permitted?

"Permission denied" (EACCES) means file permissions or a security policy refused access. "Operation not permitted" (EPERM) means the action itself is not allowed for this process, regardless of permission bits: for example changing an immutable file, or an operation that needs a capability the process lacks.

How do I remove a file that root cannot delete?

Check for the immutable or append-only attribute with lsattr file. If you see i or a, run sudo chattr -i -a file and delete it, after making sure the attribute was not set deliberately.

Why can't I chmod files on my USB stick?

FAT32, exFAT and NTFS do not store Linux permissions. Ownership and modes come from mount options such as uid, gid and umask, so set those when mounting instead of using chmod or chown.

Should I use docker run --privileged to fix it?

Only as a temporary test. --privileged gives the container nearly full control of the host. Add the specific capability instead, for example --cap-add=NET_ADMIN, or a device with --device.

Spotted a mistake or a command that no longer works? Send a correction — pages are re-checked when reports come in.