PermissionError: [Errno 13] Permission denied
1 · The lesson
readWhat this error means
The path exists, but the OS refused the operation because your process does not have permission for it.PermissionError is how Python reports the C errors EACCES (errno 13) and EPERM (errno 1). It is a subclass of OSError, so except OSError catches it. The cause is usually one of these: file system permission bits, ownership, an exclusive lock held by another process, or a security policy (SELinux, Windows ACL, AV).
When you see it
Traceback (most recent call last):
File "save.py", line 3, in <module>
with open("/etc/hosts", "w") as f:
PermissionError: [Errno 13] Permission denied: '/etc/hosts'On Windows you often see this when a file is open elsewhere:
PermissionError: [Errno 13] Permission denied: 'report.xlsx'
Why it happens
Cause 1: you don't own the path. Writing to /etc/, /usr/, C:\Windows\, or another user's home raises this.
Cause 2: the file is locked. On Windows, a file open in Excel, Word, or even Explorer's preview pane cannot be overwritten. On macOS and Linux, file locks are usually advisory, so a lock held by another program does not normally cause this error.
Cause 3: you opened a directory as a file (open("logs/")). Some systems return IsADirectoryError, and others return PermissionError.
Cause 4: antivirus, EDR, or a sandbox silently denies access to common malware locations (Temp, Startup, Documents on macOS).
Cause 5: the permission bits don't allow it. After chmod 000 file, open(file) raises this error.
How to fix it
Option 1: write to a path you own, such as your home directory, a temp directory, or your project folder.
from pathlib import Path out = Path.home() / "report.txt" out.write_text("...")
For files you only need for a short time, use tempfile:
import tempfile from pathlib import Path with tempfile.NamedTemporaryFile("w", delete=False, suffix=".csv") as f: f.write("a,b\n1,2\n") print("wrote", f.name)
Option 2: close the file in the other program. On Windows, the cause is almost always Excel keeping an .xlsx file open. Close it and try again. Writing to a .tmp file and renaming it doesn't get around the lock (the rename fails with the same PermissionError while the file is open elsewhere), but it does stop anyone reading a half-written file:
from pathlib import Path final = Path("report.xlsx") tmp = final.with_suffix(".xlsx.tmp") tmp.write_bytes(payload) tmp.replace(final) # atomic on the same drive, but fails while another program has `final` open
setup added so this can run · defines payload
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) payload = _AutoMock('payload')
Option 3: check and fix the permission bits (POSIX).
ls -l data.txt chmod u+w data.txt
Option 4: don't run as admin to "fix" it. If your code needs admin to write somewhere, that is a design bug. Pick a user-writable location.
When you'd see this in real code
- A scheduled script writes to
C:\ProgramData\MyApp\and works on the developer's machine (admin) but not on a user's (standard). - Saving a report while the user has the previous version open in Excel.
- Docker container writes to a bind-mounted directory owned by a different UID on the host.
- A script run from Terminal on macOS tries to read
~/Documentsbefore Terminal has been allowed access to that folder (System Settings > Privacy & Security > Files and Folders).
Related errors
FileNotFoundError: the path doesn't exist at all. See error-filenotfounderror.IsADirectoryError: you tried to open a directory as a file.OSError: [Errno 30] Read-only file system: the volume itself is mounted read-only.
See Also
- All Python errors: the full index, by type and by when it happens.
- File I/O: safe write patterns.
- pathlib:
Path.home(),Path.replace(). - cheat-files: fast lookup.
Found this useful? Share it with a friend who’s learning Python.