AI Agent Worktree index.lock Permission Denied
Prepared and checked using AI. Sources are linked in the article.
An AI agent worktree can show index.lock: Permission denied even while the agent edits source files because those writes go to different places. In a linked Git worktree, the index and other Git metadata live in the main repository’s .git area, which may sit outside the agent’s writable sandbox. The error identifies a blocked Git metadata write; it does not mean the source edit failed.
Why editing works but staging fails
A linked worktree contains a .git pointer file rather than a complete, independent .git directory. Its working files live in the worktree, while its private HEAD and index normally live under the main repository’s .git/worktrees/ directory. Branch refs and objects are shared with the main repository. That arrangement lets agents work on separate files and branches without giving each one a separate object database, but a sandbox that permits the worktree path alone may still block Git’s metadata path. For more on that layout, see Git worktrees explained.
git add records file contents in the index. Git must create an index.lock beside that index while updating it. A normal git commit uses staged contents, and git commit -a stages tracked changes as part of committing; neither form avoids the need to write Git metadata. Passing a filename to git commit does not turn it into a source-file-only operation.
For example, suppose the main checkout is /projects/api and the agent works in /projects/api-tasks/auth. The source file may be /projects/api-tasks/auth/src/login.ts, while the index lock is /projects/api/.git/worktrees/auth/index.lock. Granting write access to the first path does not necessarily grant it to the second. The actual worktree metadata directory can have a different name, so resolve it with Git instead of constructing it from the folder name.
Find the path Git is trying to write
Run these commands from the failing worktree, preferably in the same agent command environment that reported the error. git rev-parse --git-path resolves Git’s paths while accounting for worktrees and path overrides.
git rev-parse --show-toplevel
git rev-parse --path-format=absolute --git-dir
git rev-parse --path-format=absolute --git-common-dir
git rev-parse --path-format=absolute --git-path index
The last output is the index path; append .lock to find the lock path. --git-dir identifies this worktree’s private administrative directory. --git-common-dir identifies the shared repository metadata. Keep both paths when checking a sandbox rule: staging needs the private index and access to the shared object store, while committing also updates shared branch history. If GIT_INDEX_FILE is set, --git-path index accounts for that override, another reason to ask Git for the path.
Read the complete error before changing permissions. Git distinguishes an existing lock from other failures: an existing lock produces a message about another Git process or a stale lock, while Permission denied or Read-only file system points to a failed attempt to create the lock at that path. The latter message alone cannot tell you whether the cause is a sandbox policy, operating-system permissions, a read-only mount, or an access-control rule.
Do not delete an index.lock merely because its name appears in a permission error. First establish that the file exists and that no Git operation is using it. Removing an active lock can interfere with another writer; removing a nonexistent lock cannot repair a denied directory.
Narrow down the boundary
Use one changed file as the staging probe. Before running it, inspect existing staged changes for that file: git add -- src/login.ts stages the file’s current contents and can replace a deliberately partial staged selection. Choose a file with no staged changes if you need to preserve that selection. In the agent’s environment, run git add -- src/login.ts, substituting an actual changed path. Then run the identical command from a normal terminal opened in the same worktree. These outcomes guide the next step:
| Result | What to check next |
|---|---|
| Agent fails; normal terminal succeeds | Compare the agent sandbox’s writable paths with the resolved index and common Git directories. |
| Both fail with a permission error | Check ownership, directory access, mount mode and local access-control rules on the resolved metadata path. |
| Error says a lock already exists | Check for an active Git operation before treating the lock as stale. |
| Staging succeeds but commit fails | Check the new failing path: the commit may need a shared ref or log file, not just the worktree index. |
Keep the error text and path together. An error under .git/worktrees/<name>/index.lock identifies an index update. An error under .git/refs/ identifies a ref update. Granting access to only the first directory can allow staging while leaving commits blocked.
In Codex’s workspace-write mode, .git and a linked worktree’s resolved Git directory are protected as read-only, even when they are inside a writable root. Adding the main .git directory as another writable path therefore is not a dependable fix for that mode. An interactive session can use codex --sandbox workspace-write --ask-for-approval on-request so a blocked operation can request approval; whether it proceeds depends on the active policy. With --ask-for-approval never, the agent cannot use that approval path.
Claude Code’s sandbox describes different linked-worktree behavior: it allows writes to the main repository’s shared .git directory for Git operations when the working directory is a linked worktree, while protecting hooks/ and config. If a Claude Code session still fails, check its effective sandbox configuration, explicit denied paths, operating-system permissions and the exact failing path. Its sandbox.filesystem.allowWrite setting grants subprocess access to selected paths outside the working directory, but a broader grant should follow the diagnosis, not precede it.
Choose who should write Git history
The simplest recovery is to let the agent finish its file edits and have a trusted terminal stage and commit from that same worktree. git status --short shows staged, unstaged and untracked paths; git diff and git diff --cached separate unstaged changes from the staged snapshot. Review both before committing:
git status --short
git diff -- src/login.ts
git add -- src/login.ts
git diff --cached
git commit -m "Update login handling"
Use the worktree’s directory and branch, not the main checkout, when running these commands. Stage specific paths to avoid collecting unrelated generated files. If staging fails in the normal terminal too, stop at the permission diagnosis; retrying as a different privileged user can leave Git metadata owned by that user and complicate later work.
If the agent must create commits unattended, the sandbox or runner needs deliberate access to the required Git metadata. Check the private worktree directory, shared object storage, and the refs the task may update. That grant is wider than permission to edit source files: Git’s shared metadata connects every linked worktree. A narrowly scoped, trusted Git operation or a separate review-and-commit step is easier to reason about than making the whole shared .git tree writable to every agent.
A workflow can also keep agents in edit-only mode. Have each agent report its changed paths, review the diff, and make the commit in a trusted context. That avoids giving the agent permission to rewrite shared refs and still preserves the worktree’s value for parallel file edits. The code review workflow covers what to inspect before accepting an agent’s changes.
Where Parallel Code fits
Parallel Code is our free, MIT-licensed desktop app for macOS and Linux. It runs Claude Code, Codex CLI, Gemini CLI and other supported agents in parallel, each in its own Git worktree, and provides a diff-first review surface for their changes. The Git metadata permissions described above still depend on the agent CLI and its sandbox.
Frequently asked questions
Does index.lock: Permission denied mean another agent is committing?
Not by itself. A lock that already exists and a failed attempt to create one are different cases; use the complete error text and the resolved lock path to distinguish them. Check for an active Git process before removing any existing lock.
Why can git status work when git add fails?
Status can show useful working-tree information while the command that updates the index cannot create its lock. Treat a successful status command as evidence that Git can read enough metadata for that operation, not as proof that the sandbox can write metadata.
Can I commit from the main checkout instead?
A linked worktree has its own index and HEAD, so changing directories changes the Git state you operate on. Open a trusted terminal in the agent’s worktree and review, stage and commit there if you want that worktree’s changes and branch.
Should I grant the agent write access to the entire .git directory?
Only if that access matches your trust model and the agent’s sandbox actually permits it. Shared Git metadata includes objects and refs used by other worktrees, so a narrower commit step or an approved operation gives you a clearer boundary.