Fix: Python PermissionError: [Errno 13] Permission denied
Part of: Python Errors
Quick Answer
How to fix Python PermissionError Errno 13 Permission denied when reading, writing, or executing files, covering file permissions, ownership, virtual environments, Windows locks, and SELinux.
The Error
You run a Python script and get:
Traceback (most recent call last):
File "app.py", line 5, in <module>
with open("/var/log/myapp.log", "w") as f:
PermissionError: [Errno 13] Permission denied: '/var/log/myapp.log'Or variations like:
PermissionError: [Errno 13] Permission denied: '/usr/local/lib/python3.12/site-packages/somepackage'PermissionError: [Errno 13] Permission denied: 'output.csv'Python tried to access a file or directory and the operating system refused. Your user account does not have the required permission for the operation you attempted (read, write, or execute).
Why This Happens
Every file on Linux and macOS has owner, group, and permission attributes. On Windows, files have ACLs (Access Control Lists). When Python opens a file, the OS checks whether the current user has permission for the requested operation.
Python is a thin wrapper around the operating system’s open() syscall here. The interpreter does not have its own permission model. When the kernel returns EACCES (errno 13), Python wraps that into PermissionError. That means every workaround on the Python side ultimately reduces to “ask the OS for something the user is allowed to do” — either by changing the file’s permissions, by running as a different user, or by writing to a location where the user already has permission.
The most common causes:
- Writing to a system directory (
/usr/,/var/,/etc/) without root/admin privileges. - File owned by a different user. The file was created by
rootor another user, and your account cannot access it. - File is read-only. The write permission bit is not set.
- Directory does not allow listing or writing. You need execute permission on a directory to access files inside it.
- Windows file lock. Another process has the file open exclusively.
- Antivirus or security software is blocking access.
- SELinux or AppArmor policies are restricting file access beyond standard Unix permissions.
- Trying to write to a read-only filesystem (like a Docker container’s root filesystem or a mounted CD/USB).
Version History That Changes the Failure Mode
The POSIX file-mode model itself has not changed in decades, but how that model interacts with Python on modern developer machines absolutely has. Containers, WSL, and Apple Silicon each introduce their own permission-related pitfalls that older articles miss.
- Docker 20.10 (Dec 2020) — rootless mode GA. Before rootless, Docker mounted volumes with files owned by
rootinside the container, and your host user could not edit them withoutsudo. Rootless Docker runs the daemon as your unprivileged user, so file ownership across the bind mount is your UID on both sides. If your team mixes rootless and rootful Docker installs, the same Compose file produces different file-ownership outcomes — and differentPermissionErrorsymptoms inside the container. - Docker user namespaces (since 1.10, refined throughout 2020-2023). When enabled, container UIDs are remapped to a different host-side range (for example, container UID 0 becomes host UID 100000). A file you
chmod 644on the host appears owned by a UID your container does not recognise. If your team enabled user namespaces in 2022 and someone joins now without that config, bind-mounted writes work for one developer and fail for the other. - WSL 2 (June 2019, refined through 2024). WSL 2 runs Linux in a real VM. Filesystem behaviour depends on which filesystem you write to: files inside the Linux filesystem (
/home/...) have normal Unix permissions, but files on/mnt/c/(Windows drives) are bridged through DrvFs. Withoutmetadatamount options enabled in/etc/wsl.conf,chmodon a/mnt/cfile is silently ignored. This bridge has been refined repeatedly in WSL updates; if your/etc/wsl.confis from 2020 you may want to revisit it. - Apple Silicon (Nov 2020 onward). Docker Desktop on M1/M2/M3 macs runs Linux containers under a virtualisation framework. Volume mounts go through a file-sharing layer (originally
osxfs, latergRPC FUSE, more recently VirtioFS). Each version handled UID mapping slightly differently, which is why “I cannot write to my bind mount” reports cluster around specific Docker Desktop releases. As of recent Docker Desktop versions, VirtioFS is the default and the failure mode is largely “wrong UID inside the container,” fixable with--user $(id -u):$(id -g). - Linux capabilities and unprivileged user namespaces. Modern container runtimes can grant fine-grained capabilities instead of full root. A container that has
CAP_DAC_OVERRIDEcan bypass file ownership, while one without it hits this error even when running as UID 0. KubernetessecurityContextcontrols these caps — if your pod hasallowPrivilegeEscalation: false, you may see a permission denied on operations that work on your laptop. - macOS Ventura+ (Oct 2022) — extended TCC prompts. Recent macOS releases prompt for access to Documents, Downloads, Desktop, and removable volumes. The first time a Python script tries to write there from Terminal or VS Code, you get this exact error until you grant the parent application Full Disk Access (or specifically the listed folder) in System Settings → Privacy & Security.
- Windows 11 Controlled Folder Access. When this feature is enabled, Defender blocks “untrusted” apps (including
python.exe) from writing to Documents, Pictures, Desktop, etc. The OS returns access-denied, which Python reports asPermissionError. Addpython.exeto the allowed list in Windows Security.
If your script “worked yesterday and not today,” check whether the platform layer changed — Docker Desktop auto-updated, WSL was upgraded, Apple shipped a security update — before suspecting your code.
Fix 1: Check and Fix File Permissions
First, check the current permissions:
ls -la /path/to/fileOutput:
-rw-r--r-- 1 root root 1234 Mar 9 10:00 myfile.txtThis means: owner (root) can read/write, group and others can only read. If your user is not root, you cannot write to this file.
Change permissions:
chmod 664 /path/to/file # Owner and group can read/write, others can read
chmod 666 /path/to/file # Everyone can read/writeChange ownership to your user:
sudo chown $USER:$USER /path/to/fileFor directories, apply recursively:
sudo chown -R $USER:$USER /path/to/directoryThis is the same approach used for fixing bash permission denied errors — the underlying cause is identical.
Common Mistake: Using
chmod 777to fix permission issues. This gives everyone full read, write, and execute access, which is a security risk. Use the minimum permissions needed:644for files (owner writes, others read) and755for directories.
Fix 2: Don’t Write to System Directories
If your script tries to write to /usr/, /var/log/, /etc/, or other system directories, that is the problem. Normal users should not write to these locations.
Fix: Write to user-accessible locations:
import os
from pathlib import Path
# Write to the user's home directory
home = Path.home()
log_file = home / "myapp" / "app.log"
log_file.parent.mkdir(parents=True, exist_ok=True)
with open(log_file, "w") as f:
f.write("log entry\n")Or use a temporary directory:
import tempfile
with tempfile.NamedTemporaryFile(mode="w", suffix=".log", delete=False) as f:
f.write("temporary log")
print(f.name) # /tmp/tmpXXXXXX.logFor application data, use platform-appropriate directories:
import os
# Linux: ~/.local/share/myapp
# macOS: ~/Library/Application Support/myapp
# Windows: C:\Users\<user>\AppData\Local\myapp
data_dir = os.path.join(os.path.expanduser("~"), ".local", "share", "myapp")
os.makedirs(data_dir, exist_ok=True)Fix 3: Use Virtual Environments Instead of sudo pip
If the error happens during pip install:
PermissionError: [Errno 13] Permission denied: '/usr/local/lib/python3.12/site-packages/...'Do not use sudo pip install. This installs packages system-wide, which can conflict with system Python and break OS tools.
Fix: Use a virtual environment:
python -m venv venv
source venv/bin/activate # Linux/macOS
# or: venv\Scripts\activate # Windows
pip install some-package # Installs to venv, no sudo neededIf you see externally-managed-environment errors on newer systems, see Fix: pip externally managed environment.
Pro Tip: Always use virtual environments for Python projects. They isolate dependencies, prevent permission issues, and avoid conflicts between projects. Tools like
poetry,pipenv, anduvcreate virtual environments automatically.
Fix 4: Fix Directory Permissions
If the error points to a directory rather than a file, you need execute permission on the directory to access its contents:
ls -la /path/to/Directories need the execute bit (x) for traversal:
chmod 755 /path/to/directory # Owner: rwx, Group/Others: rxA common scenario: your script creates a subdirectory but the parent directory doesn’t allow writing:
os.makedirs("/opt/myapp/data", exist_ok=True)
# PermissionError if /opt/ doesn't allow writingFix: Create the directory in a writable location, or use sudo to create it once and change ownership:
sudo mkdir -p /opt/myapp/data
sudo chown -R $USER:$USER /opt/myappFix 5: Handle Windows File Locks
On Windows, a file can be locked exclusively by another process. If Excel, a text editor, or another Python script has the file open, your script cannot write to it:
PermissionError: [Errno 13] Permission denied: 'report.xlsx'Fix: Close the other program that has the file open. Or check which process holds the lock:
# Find processes using the file
Get-Process | Where-Object { $_.Modules.FileName -like "*report.xlsx*" }Or use tools like Process Explorer or Handle from Sysinternals.
In your code, handle the error gracefully:
import time
def write_with_retry(filepath, content, retries=3):
for attempt in range(retries):
try:
with open(filepath, "w") as f:
f.write(content)
return
except PermissionError:
if attempt < retries - 1:
time.sleep(1)
else:
raiseFix 6: Handle Antivirus and Security Software
Antivirus programs (Windows Defender, Norton, McAfee, etc.) can block Python from writing to certain locations. This is especially common with:
- Files in the Downloads folder
- Executable files (
.exe,.bat,.ps1) - Files matching patterns that look like malware
Fix: Add your project directory to the antivirus exclusion list. For Windows Defender:
- Open Windows Security → Virus & threat protection
- Click “Manage settings” under “Virus & threat protection settings”
- Scroll to “Exclusions” → “Add or remove exclusions”
- Add your project folder
Fix 7: Check SELinux and AppArmor (Linux)
On RHEL, CentOS, Fedora, and Amazon Linux, SELinux can block file access even when Unix permissions allow it. The error looks identical to a regular permission denied.
Check if SELinux is enforcing:
getenforceIf it returns Enforcing, check the SELinux audit log:
sudo ausearch -m avc -ts recentFix the SELinux context for your files:
sudo restorecon -Rv /path/to/filesOr set a permissive context for your application directory:
sudo chcon -R -t httpd_sys_rw_content_t /path/to/writable/dirOn Ubuntu, AppArmor can cause similar issues. Check its status:
sudo aa-statusFix 8: Use os.access() to Check Before Opening
Instead of crashing on PermissionError, check permissions first:
import os
filepath = "/path/to/file"
if os.access(filepath, os.W_OK):
with open(filepath, "w") as f:
f.write("data")
else:
print(f"No write permission for {filepath}")Available checks:
| Flag | Checks |
|---|---|
os.R_OK | Read permission |
os.W_OK | Write permission |
os.X_OK | Execute permission |
os.F_OK | File exists |
Note: There is a TOCTOU (time-of-check-time-of-use) race condition with this approach. The permission could change between the check and the open. For critical applications, use try/except instead:
try:
with open(filepath, "w") as f:
f.write("data")
except PermissionError:
print(f"Cannot write to {filepath}")Fix 9: Handle Docker Container Permissions
Inside Docker containers, permission errors are common when:
- The container runs as root but the mounted volume was created by a different user
- The container runs as a non-root user but needs to write to directories created during build
Fix volume permission issues:
docker run -v /host/path:/container/path -u $(id -u):$(id -g) myappThe -u flag runs the container as your host user, matching file ownership.
Or fix permissions in the Dockerfile:
RUN mkdir -p /app/data && chown -R 1000:1000 /app/data
USER 1000For more Docker volume permission issues, see Fix: Docker volume permission denied.
Still Not Working?
If none of the fixes above resolved the error:
Check for read-only filesystems. Some Docker containers, Kubernetes pods, or cloud environments mount the root filesystem as read-only. Write to /tmp or a mounted volume instead.
Check for NFS or network mount issues. Network-mounted filesystems may have different permission rules. root_squash on NFS servers prevents root from writing. Contact your sysadmin for NFS permission issues.
Check Python’s own file. If the error is during python script.py, check that the script file itself is readable:
chmod 644 script.pyIf Python itself isn’t found rather than blocked, see Fix: python command not found.
Check for immutable flags. On Linux, files can be marked immutable with chattr:
lsattr /path/to/fileIf you see i in the flags, the file cannot be modified even by root:
sudo chattr -i /path/to/fileUse strace to debug (Linux):
strace -e openat python script.py 2>&1 | grep EACCESThis shows exactly which file system call is failing and why.
Check WSL /mnt/c metadata. If you are on WSL 2 and writing to a path under /mnt/c/, chmod is silently ignored unless you enable metadata in /etc/wsl.conf:
[automount]
options = "metadata,uid=1000,gid=1000,umask=22,fmask=11"Restart WSL (wsl --shutdown from PowerShell, then re-open) and re-run. Without this, your script can read but cannot toggle permissions on Windows-side files at all.
Check macOS TCC permissions on Ventura and later. If the file lives in Documents, Downloads, Desktop, or on an external volume, macOS may be blocking your terminal or editor, not Python itself. Open System Settings → Privacy & Security → Full Disk Access (or Files and Folders) and add Terminal, iTerm, or your editor. The OS-level error is indistinguishable from a normal EACCES.
Check Kubernetes securityContext and runAsNonRoot. Pods that set runAsNonRoot: true, readOnlyRootFilesystem: true, or drop CAP_DAC_OVERRIDE will see this error on operations that would succeed on a standard Linux host. Either mount an emptyDir volume to a writable path, or relax the security context where appropriate. Confirm with kubectl describe pod <name> and look at the security context fields.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: joblib Not Working — Parallel Backends, Memory Cache, and Pickling Errors
How to fix joblib errors — Parallel n_jobs slower than expected, Memory cache miss, backend loky vs threading vs multiprocessing, pickling lambda not supported, dump load file size, and pytest interference.
Fix: Marshmallow Not Working — Schema Errors, Load vs Dump, and Field Validation
How to fix Marshmallow errors — Schema not validated on dump, ValidationError messages format, unknown field handling, missing vs default, post_load object construction, and Marshmallow 3 to 4 migration.
Fix: Pipenv Not Working — Lock File Generation, Shell Activation, and Dependency Resolution
How to fix Pipenv errors — pipenv lock takes forever, Pipfile.lock not generated, shell activation broken, no virtualenv created, dependency conflict, and migration to uv or Poetry.
Fix: Copier Not Working — Template Updates, Question Conditions, and Migrations
How to fix Copier errors — copier.yml not found, conditional questions not appearing, update breaks generated project, migrations between versions, Jinja vs YAML escaping, and answers file conflict.