# Claude Code permission denied when editing files: how to fix workspace and sandbox access
“Claude Code Permission Denied When Editing Files” usually means one of two things: Claude Code is not allowed to edit that path, or the Unix user running Claude Code cannot write to the file. The fix that worked for me was to start in the right workspace, check `/permissions`, and then check directory ownership before blaming the model.
I ran into this while trying to patch a small config file from inside Claude Code. The edit was harmless. The file existed. The path was right. Claude could read it, explain it, and propose the exact diff. Then the write step failed with the most boring error in computing:
“`text
Permission denied
“`
In another run, the same failure appeared as a Node-style filesystem error:
“`text
Error: permission denied while opening ‘/srv/app/config/settings.json’
“`
That error is annoying because it can come from Claude Code, the sandbox, or Linux permissions. In my case, all three mattered, just not in the order I expected.
## The setup I was using
The stack was simple:
“`text
Claude Code running in a terminal
Ubuntu server
A project checked out under ~/projects/app
Some service files under /srv/app
A normal non-root shell user
“`
I was asking Claude Code to edit files while my shell was in a workspace directory. The important detail is that Claude Code permissions define which tools and paths it may use, while Linux permissions still apply underneath. Claude Code can be allowed to use `Edit`, and the operating system can still reject the write.
The official Claude Code permissions model treats those as separate layers. Permissions control which tools Claude Code can use and which files or domains it can access. File modification is approval-gated, permission rules can be managed from `/permissions`, and sandbox settings can limit where shell commands write. None of that changes whether the current Unix user owns the target file.
My mistake was treating “Claude can read this file” as “Claude can edit this file.” Those are different checks.
## The wrong path: approving the same edit again and again
My first instinct was to approve the edit again. That felt reasonable because Claude Code has an approval flow for file changes. If the tool asks for permission, surely the fix is to approve it harder, right?
No. Clicking harder is still a terrible debugging strategy.
The misleading part is that Claude Code may inspect the file and propose a patch before the write fails. The session can feel authorized even when the final write is blocked. You might see a flow like this:
“`text
Read(file) -> allowed
Edit(file) -> requested
User approval -> granted
Write attempt -> Permission denied
“`
That does not mean the approval failed. It means a lower layer refused the actual write.
I also tried launching Claude Code again from a nearby directory. That did not help because the file I wanted to edit was outside the active project workspace. Claude Code’s permission settings and the shell’s current working directory both matter. Starting from your home directory and editing a deployment directory is not the same as starting from that deployment directory.
A second wrong path was reaching for `sudo` immediately:
“`bash
sudo claude
“`
I would not make that the default fix. Running an agent as root just to edit one file widens the blast radius. If the file has the wrong owner, fix the owner. If Claude Code is scoped to the wrong workspace, start it in the right workspace. Use root only when you are intentionally editing root-owned system files and understand the risk.
## Claude Code permission denied when editing files: the fix
This is the checklist I use now. It separates workspace scope, Claude Code tool permission, and Unix filesystem permission. Run it in this order.
### 1. Start Claude Code from the directory you actually want it to edit
Before opening Claude Code, move into the project root. Use a real path on your machine, not a copied path from someone else’s server:
“`bash
cd ~/projects/app
pwd
“`
The expected output should be the project you intend to modify. On many systems, `pwd` expands `~` to the full home-directory path, which is fine as long as it is your own local path.
Claude Code permission decisions depend on the project context. If you start the session from a parent folder, a sibling folder, or a random deployment directory, you can end up asking it to edit outside the area you meant to grant.
If the file is really under a deployment directory, start there instead:
“`bash
cd /srv/app
claude
“`
Do not rely on “it is only one directory away.” Workspace boundaries are exactly where these bugs hide.
### 2. Check Claude Code permissions with `/permissions`
Inside Claude Code, open the permissions UI:
“`text
/permissions
“`
Look for rules that affect file edits and shell commands. The rule categories that matter are:
“`text
Allow: permits a tool or pattern
Ask: prompts before use
Deny: blocks a tool or pattern
“`
The order matters: deny rules win before ask or allow rules. A broad deny can block a narrower allow. So if you have something like this conceptually:
“`text
Deny Edit(/srv/*)
Allow Edit(/srv/app/*)
“`
The deny still wins. Adding more allow rules under a broad deny will not fix it. Remove or narrow the deny rule.
Claude Code permissions are enforced by Claude Code, not by the prompt. Writing “you are allowed to edit this file” in a project instruction file or the chat does not override a deny rule.
### 3. Confirm the file is writable by the current Unix user
Now check the actual filesystem owner and mode:
“`bash
ls -ld .
ls -l path/to/file
id
“`
A healthy project file usually looks boring:
“`text
drwxr-xr-x 8 appuser appuser 4096 Jun 20 12:10 .
-rw-r–r– 1 appuser appuser 1842 Jun 20 12:11 path/to/file
uid=1000(appuser) gid=1000(appuser) groups=1000(appuser)
“`
If you see `root root` on a file you expect to edit as `appuser`, that is the real problem:
“`text
-rw-r–r– 1 root root 1842 Jun 20 12:11 path/to/file
“`
Fix ownership when the file should belong to your app user:
“`bash
sudo chown appuser:appuser path/to/file
“`
Or fix a whole project tree if root accidentally created it. Replace the path with your own project directory:
“`bash
sudo chown -R appuser:appuser ~/projects/app
“`
Claude Code is not magic. Its edit tool still writes through the process user. If that user cannot write to the file, Claude Code cannot write to the file either.
### 4. Test a normal shell write before asking Claude Code to edit again
Use a harmless write test in the target directory:
“`bash
touch .claude-write-test && rm .claude-write-test
“`
If that fails, Claude Code will fail too:
“`text
touch: cannot touch ‘.claude-write-test’: Permission denied
“`
Fix the directory permission before continuing. If it succeeds silently, the operating system layer is probably fine, and you can return to Claude Code permissions.
A plain `touch` removes the model from the diagnosis. It is the fastest way to find out whether the problem is Claude Code or Linux.
### 5. If the file is intentionally outside the workspace, add access deliberately
Sometimes the target really does live outside the repo: generated assets, deployment config, a shared package, or a mounted volume. In that case, do not work around Claude Code by starting from `/` or running as root. Add the path through the normal permission flow.
Inside Claude Code:
“`text
/permissions
“`
Then allow the specific path or tool pattern you need. Keep it narrow. Prefer allowing one project directory over allowing your whole home directory, or worse, the entire server.
A good mental model:
“`text
Good: allow edits in /srv/app
Risky: allow edits in /srv
Bad: allow everything because I am tired
“`
The goal is to make the intended edit possible without making every future edit too broad.
## Verification: how I know the fix held
After changing the workspace and ownership, I verify from both sides.
First, the shell write test:
“`bash
cd /srv/app
touch .claude-write-test && rm .claude-write-test
“`
No output is good output.
Second, I ask Claude Code for a tiny reversible edit, usually a comment or whitespace-only patch in a disposable file. If it can create and remove a temporary file in the same directory, the edit path is working:
“`bash
printf ‘ok\n’ > .claude-edit-test
cat .claude-edit-test
rm .claude-edit-test
“`
Expected output:
“`text
ok
“`
Third, I check that I did not accidentally create root-owned files during the fix:
“`bash
find . -maxdepth 2 -user root -print
“`
For a normal user-owned project, that should return nothing. If it prints project files, I clean up ownership before continuing.
The final confirmation is boring: Claude Code applies the patch, the file changes, and `git diff` shows only the expected edit.
“`bash
git diff — path/to/file
“`
If `git diff` is clean except for the intended patch, the problem is fixed.
## Edge cases and gotchas
– Docker bind mounts can lie to you. If the file lives in a bind-mounted directory, check permissions on the host and inside the container. A path may look writable in one layer and fail in the other.
– Remote servers add another user boundary. If you SSH as `deploy` but the app files are owned by `www-data`, Claude Code inherits the `deploy` user’s limits. Fix the deployment ownership model instead of giving the agent blanket root access.
– Deny rules beat your prompt. If `/permissions` has a broad deny rule, no amount of “please edit this file” in the chat will override it. Change the permission rule.
– `sudo claude` creates cleanup work. It may solve the immediate edit, but it can also leave root-owned generated files in your repo. That turns one permission error into ten smaller ones later.
– Read access is not write access. Claude Code can often inspect files it cannot modify. Treat a successful read as a clue, not proof that edits are allowed.
## The rule I use now
When Claude Code hits “Permission denied” while editing files, I do not start with the model. I start with the path.
The shortest reliable diagnosis is:
“`bash
pwd && ls -ld . && ls -l path/to/file && touch .claude-write-test && rm .claude-write-test
“`
If that passes, I check `/permissions`. If that fails, I fix Unix ownership or directory mode. Keeping those two layers separate has saved me from a lot of fake debugging.
## TL;DR fix
“`bash
cd /path/to/the/actual/project && claude # then check /permissions and confirm: touch .claude-write-test && rm .claude-write-test
“`
## Sources checked
I checked the current Claude Code documentation for permissions, settings, security boundaries, and sandbox behavior while revising this troubleshooting flow. The practical point is the same: Claude Code approval, sandbox scope, and Unix filesystem ownership are separate layers, so diagnose them separately.
