Fix Errno 13 Permission Denied: A Complete Guide (2026)

Updated May 22, 2026 By Server Scheduler Staff
Fix Errno 13 Permission Denied: A Complete Guide (2026)

meta_title: Fix Errno 13 Permission Denied Guide for DevOps Teams meta_description: Learn how to diagnose errno 13 permission denied across local systems, Python, Node.js, containers, and cloud workflows with practical fixes. reading_time: 7 minutes

You're usually staring at this error at the worst possible moment. A deploy script fails, a build breaks, a Python job can't write output, or a container that worked yesterday suddenly throws Errno 13 permission denied today. The frustrating part is that the message looks simple, but the underlying cause often sits one layer lower than the code you're reading.

If you want fewer late-night permission hunts and more predictable infrastructure, Server Scheduler helps teams automate cloud operations without maintaining brittle scripts for routine start, stop, resize, and reboot tasks.

Ready to Slash Your AWS Costs?

Stop paying for idle resources. Server Scheduler automatically turns off your non-production servers when you're not using them.

Diagnosing the Root Cause on Your Local Machine

Start with the user, the path, and the operation that failed. That simple triage saves time because Errno 13 permission denied on a local machine usually comes from the operating system layer, even when it surfaces inside Python or another runtime. The process tried to read, write, execute, create, rename, or traverse something the current user account could not access.

A developer looking at a computer screen displaying a Linux file permission denied error.

A common failure looks like this: a script tries to write /var/app/output/report.csv, but /var/app/output is owned by another user or group. Check the parent directory, not just the file name in the error. If the directory is not writable by the account running the process, the script will fail every time, whether you launch it from a terminal, IDE, or scheduler.

Run ls -l on the target file and ls -ld on each parent directory in the path. That tells you who owns the path, which group applies, and whether your user can traverse and modify it. If you need a quick command reference while debugging, keep this Bash commands cheat sheet open.

Read the permission bits before changing anything

On Linux and macOS, r allows reading, w allows writing, and x allows execution. For directories, the execute permission controls traversal. A directory can show up in a listing and still block access because your process cannot enter it.

That detail trips people up all the time.

Symptom Potential Cause Diagnostic Command Fix Command Example
Script can't read a file Wrong owner or missing read permission ls -l file.txt chown appuser:appgroup file.txt
Script can't write output Parent directory not writable ls -ld /path/to/output chmod u+w /path/to/output
Script can't enter a directory Missing execute permission on directory ls -ld /path/to/dir chmod u+x /path/to/dir
Command works as root but not app user Ownership mismatch id and ls -l chown -R appuser:appgroup /path/to/app

Practical rule: Don't use chmod 777 as a shortcut. It hides the underlying ownership problem, grants far more access than the process needs, and usually creates a mess you have to clean up later.

Ownership is only one branch of the diagnosis. The path itself may be wrong.

Check whether the path is even a file

A lot of Errno 13 cases come from code opening a directory as if it were a file. I see this in scripts where output_path resolves to /var/app/output/ instead of /var/app/output/report.csv. The error looks like a permissions problem, but the actual fix is to validate the resolved path before the code touches it.

Check whether the target is a regular file, a directory, or a symlink. Then verify that every directory in the path is accessible to the current user. On Windows, also check whether another process has the file open, because a lock can surface as an access error that looks similar to a Unix permission issue.

Treat Errno 13 as a category, not a diagnosis. On a local machine, the root cause is usually one of four things: bad ownership, missing permission bits, a directory being used like a file, or a path that resolves somewhere different from what the code expects.

Language-Specific Scenarios in Python and Node.js

Python and Node.js do not create new permission problems. They surface the same filesystem failure through different exceptions, and the exception name can distract you from the underlying cause. In Python, you usually get PermissionError: [Errno 13]. In Node.js, you usually see EACCES, EPERM, or a failed fs call. Start with the operation that failed: open, write, rename, mkdir, or delete.

Teams can lose time by assuming every permission failure means “need more privileges.” In practice, runtime errors often come from path resolution mistakes, parent directories that are not writable, or Windows file locks that have nothing to do with Unix mode bits.

What usually fails in Python and Node.js

In Python, the classic example is:

with open(output_path, "w") as f:
    f.write(data)

That fails with Errno 13 if output_path resolves to a directory, a protected location, or a file owned by another user. I also see this after a script switches from running manually to running under cron, systemd, or a virtual environment tied to a different account. Same code, different execution context.

Node.js hits the same wall with fs.writeFile(), fs.createWriteStream(), fs.rename(), and fs.mkdir(). The common pattern is simple. The code assumes the path points to a writable file, but the resolved target is a directory, an unwritable parent, or a locked artifact left behind by another process.

If the stack trace mixes access errors with missing-path errors, compare it against this guide to Error 2 no such file or directory. The symptoms overlap because both failures happen at the moment your code touches the filesystem.

Triage by the failing operation

open() or fs.writeFile() usually points to the target path itself. Check whether the final path segment is a file, whether the parent directory exists, and which user owns both.

mkdir() or recursive directory creation usually points to an intermediate parent. Your app may have write permission on /app/output/reports, but no execute or write permission on /app/output, which blocks the whole chain.

rename() and atomic write patterns fail in ways that confuse people. Many libraries write to a temp file, then rename it into place. If the temp directory and destination live on different mounts, or if the destination file is locked on Windows, the code can surface EACCES even though the original write succeeded.

Windows needs a different mental model

On Windows, permission checks are only part of the story. File locking is the other half. Editors, antivirus tools, archive managers, File Explorer previews, and build tooling can keep a handle open long enough to break a write, replace, or cleanup step.

That matters in Python packaging and Node build pipelines. A rebuild can fail because the previous artifact is still open, not because the account lacks access. In those cases, close the process holding the file, retry the operation, and then decide whether you have an ACL problem.

Runtime context changes the answer

The same script can work from your terminal and fail inside a service manager, CI runner, Electron app, or packaged executable because the effective user, working directory, temp directory, and home directory all changed. Check os.getuid() or the Windows account context in Python. Check process.getuid?.() and process.cwd() in Node.js. Then compare that with the ownership and location of the files the runtime is touching.

This is also where containerized Node and Python apps start to blur into infrastructure work. If your app writes to bind mounts, shared volumes, or image paths that were created by root during build, fix the image and runtime model together. To reduce these failures later, harden Docker images and runtime so the app user, writable paths, and mounted volumes line up by design.

Solving Permission Errors in Containers and the Cloud

A container starts clean, the app starts fine, and then the first file write throws Errno 13. I see this pattern constantly. The bug is rarely in the line of code that failed. It is usually in the boundary between the process identity, the filesystem mounted into the container, and the platform enforcing access.

A diagram illustrating five essential cloud and container permission security strategies for managing environments effectively.

Start by asking a narrower question than "does this app have permission?" Ask which layer rejected the operation. In container and cloud environments, that answer often sits outside the application. A bind mount from the host can carry ownership the container user cannot write to. A Kubernetes volume can mount with a different security context than the image expects. A cloud transfer job can pass local file checks and still fail because the service account or IAM role lacks access to the remote target.

Compare the likely failure domains

Environment What usually fails What actually fixes it
Local Linux or macOS Ownership or mode bits Correct chown or chmod
Windows desktop Wrong path type or file lock Fix the path or release the lock
Docker build Write to a mount or restricted layer Change build strategy or target path
Docker runtime UID/GID mismatch on a volume Align container user with mounted storage
Cloud service access Identity policy mismatch Fix role or access policy

For Docker, check the running identity before changing anything else. docker exec into the container, run id, then inspect the target path with ls -ld both inside the container and on the host if it is a bind mount. If the container runs as UID 1000 but the mounted directory is owned by root with restrictive modes, the error is expected. Fix the ownership on the host, map the container to the correct UID/GID, or mount a path designed for that service account. chmod 777 will hide the problem for a day and create a bigger one later.

Image design matters too. If the image creates application directories as root during build and the runtime switches to a non-root user, writes will fail the moment the app touches cache, logs, uploads, or temp files. Build the writable paths with the final runtime user in mind. Teams that standardize how they harden Docker images and runtime spend less time chasing permission drift across laptops, CI jobs, and production clusters.

Kubernetes adds another layer. runAsUser, runAsGroup, and fsGroup can fix volume access, but only if they match the storage behavior underneath. Some CSI drivers honor those settings cleanly. Others require you to prepare the volume out of band. If a pod can write to its image filesystem but not to /data, inspect the pod security context, the volume type, and the ownership on the mounted path before touching application code.

Cloud services shift the problem from Unix permissions to service identity. An upload job that writes locally and then fails against S3, EFS, Transfer Family, or a managed file service is often hitting an IAM or resource policy issue, not a filesystem ACL issue. If your workflow crosses that boundary, this guide to SFTP in AWS is a useful reference for separating host-level permissions from service-level access control.

A short walkthrough can help if you're debugging containers in motion:

Running the container as root can make the error disappear. It also removes the signal that your ownership model is wrong. Fix the mount, the UID/GID mapping, or the cloud identity now, and the same workload will behave predictably in CI, Kubernetes, and production.

Preventative Measures and Best Practices

Permission errors stop being random once ownership, identity, and write paths are defined before deployment. Systems stay stable when every process has a clear runtime user, every writable path is intentional, and every directory has an owner that matches how the application runs.

A hand-drawn illustration depicting cybersecurity themes with a server rack, a shield, audit lists, and team cooperation.

Build around least privilege

Use dedicated service accounts instead of shared admin users. Give each app write access only to the directories, sockets, or mounted volumes it needs. In shared Unix environments, group ownership is often easier to maintain than world-writable permissions, especially when multiple services touch the same release or data path.

Path mistakes belong in the same prevention checklist. On Windows, Python can raise PermissionError when code passes a directory to open() instead of a file. That failure looks like an ACL problem even though the underlying cause is object type. Validate paths early, and fail with a clear message before the runtime reaches the filesystem call.

Treat path validation as part of permission hygiene. Correct privileges do not help if the target is the wrong object.

Make permissions part of your platform design

Mature DevOps practices include defining users, groups, runtime identities, and storage expectations in version-controlled infrastructure and deployment code. That removes the usual cycle of fixing ownership by hand after each rollout, then rediscovering the same breakage in CI or production. Review permission changes during code review, alongside ports, secrets, and volume mounts.

Cloud systems need the same discipline at the identity layer. A workload may have correct Unix ownership and still fail because its role cannot assume the right policy or write to the target service. If you are cleaning up service roles and access boundaries, a definitive guide to IAM modernization is a useful companion for that work.

Operator consistency matters too. Standardizing host aliases, usernames, keys, and jump-host settings in a shared SSH config file for repeatable remote access cuts down on one-off shell sessions that create files under the wrong account.

The goal is simple. Make the correct user, group, path, and identity the default, so errno 13 becomes a rare signal instead of a recurring maintenance task.


Server Scheduler helps DevOps teams automate server, database, and cache operations across AWS with a simple visual schedule instead of fragile scripts. If you want fewer manual maintenance tasks, cleaner operating windows, and better control over non-production infrastructure, take a look at Server Scheduler.