Linked worktree git add fails: .git/worktrees index.lock remains read-only despite --add-dir
What version of Codex is running?
Tested across multiple npm package versions of @openai/codex:
0.125.00.126.0-alpha.170.128.00.129.00.130.00.131.00.132.0
Current installed binary path in my normal environment:
/home/tangi/.nvm/versions/node/v24.0.1/bin/codex
System:
Linux tangi-t14 6.8.0-111-generic #111-Ubuntu SMP PREEMPT_DYNAMIC Sat Apr 11 23:16:02 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
Which model were you using?
gpt-5.5 in the smoke tests below.
What happened?
git add fails inside a Git linked worktree because the sandbox keeps the linked worktree index metadata read-only:
fatal: Unable to create '<main-repo>/.git/worktrees/<worktree>/index.lock': Read-only file system
This happens even when the main repo .git directory is passed with --add-dir and appears in Codex's sandbox summary.
This is related to openai/codex#7071, but the failure here is specifically for Git linked worktrees. In that case git add does not write .git/index.lock in the worktree directory. It writes under the main repo metadata path:
<main-repo>/.git/worktrees/<worktree>/index.lock
Reproduction
Use a linked worktree and allow the main repository .git directory as an additional writable directory:
MAIN=$(mktemp -d /tmp/codex-linked-main.XXXXXX)
git init "$MAIN"
printf base > "$MAIN/base.txt"
git -C "$MAIN" add base.txt
git -C "$MAIN" -c user.name=Codex -c user.email=codex@example.invalid commit -m initial
mkdir -p "$MAIN/.worktrees"
git -C "$MAIN" worktree add "$MAIN/.worktrees/task-1" -b task-1
npm exec --yes --package @openai/codex@0.132.0 -- codex exec \
--sandbox workspace-write \
-C "$MAIN/.worktrees/task-1" \
--add-dir "$MAIN/.git" \
-c 'approval_policy="never"' \
'Create file smoke.txt containing smoke, run git add smoke.txt, then git status --short. Do not commit. Report the exact output.'
Observed Codex sandbox summary includes the main .git directory:
sandbox: workspace-write [workdir, /tmp, $TMPDIR, /tmp/liza-codex-0132-nolegacy-main.20rQJ8/.git] (network access enabled)
But git add fails:
fatal: Unable to create '/tmp/liza-codex-0132-nolegacy-main.20rQJ8/.git/worktrees/task-1/index.lock': Read-only file system
git status --short afterwards:
?? codex0132-nolegacy-smoke.txt
Version matrix
Same linked-worktree smoke test, using workspace-write, --add-dir <main repo .git>, and no named permission profile unless noted:
0.125.0 without use_legacy_landlock => FAIL read-only index.lock
0.125.0 with use_legacy_landlock => PASS git add succeeds
0.126.0-alpha.17 with use_legacy_landlock => FAIL panic before shell command
0.128.0 with use_legacy_landlock => FAIL panic before shell command
0.129.0 with use_legacy_landlock => FAIL panic before shell command
0.130.0 with use_legacy_landlock => FAIL panic before shell command
0.131.0 without use_legacy_landlock => FAIL read-only index.lock
0.131.0 with use_legacy_landlock => FAIL panic before shell command
0.132.0 without use_legacy_landlock => FAIL read-only index.lock
0.132.0 with use_legacy_landlock => FAIL panic before shell command
Passing 0.125.0 legacy run:
npm exec --yes --package @openai/codex@0.125.0 -- codex exec \
--enable use_legacy_landlock \
--sandbox workspace-write \
-C /tmp/liza-codex-0125-main.qf7fvw/.worktrees/task-1 \
--add-dir /tmp/liza-codex-0125-main.qf7fvw/.git \
-c 'approval_policy="never"' \
'Create file codex0125-legacy-smoke.txt containing codex0125-legacy-smoke-test, run git add, then git status --short.'
Output:
A codex0125-legacy-smoke.txt
Failing modern legacy-landlock runs panic before executing shell commands:
thread 'main' (...) panicked at linux-sandbox/src/linux_run_main.rs:311:9:
permission profiles requiring direct runtime enforcement are incompatible with --use-legacy-landlock
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Expected behavior
There should be a supported way for automation to run git add in a linked worktree under sandboxing without danger-full-access.
If --add-dir <main repo .git> is shown as writable in the sandbox summary, git add should be able to create:
<main-repo>/.git/worktrees/<worktree>/index.lock
Alternatively, Codex should document the supported configuration for linked worktrees.
Why this matters
Multi-agent and automation workflows commonly use Git linked worktrees for isolated task execution. Without writable linked-worktree metadata, agents can edit files but cannot stage or commit them.
3 Comments
Solution: openai/codex #23661 — Linked worktree git add fails: index.lock read-only
🔍 Root Cause Analysis
When running
git addinside a Git linked worktree under Codex's sandbox, the operation fails because the sandbox keeps the linked worktree's index metadata read-only:Why This Happens
Git linked worktrees store their metadata in the main repository's
.git/worktrees/directory, NOT in the worktree directory itself. Whengit addruns in a linked worktree:The sandbox configuration passes
--add-dir "$MAIN/.git"to allow writes to the main.gitdirectory, but the Landlock sandbox (introduced in v0.125.0+) restricts filesystem access at a lower level than--add-dir.Version Matrix Analysis
Key observations:
.git/worktrees/Root Cause: Landlock Doesn't Recognize Nested
.git/worktrees/PathThe Landlock sandbox implementation likely:
.gitdirectory to the allowed paths via--add-dir.git/worktrees/directory has different permissions that Landlock interprets as read-onlyThis is a path resolution issue in the Landlock sandbox: the sandbox adds
/path/to/repo/.gitas writable, but when Git tries to write to/path/to/repo/.git/worktrees/task-1/index.lock, Landlock doesn't recognize this as within the allowed path.🛠️ Proposed Fix
Fix 1: Ensure Landlock Rules Propagate to Nested Paths (Primary Fix)
The Landlock sandbox must ensure that
--add-dirrules propagate to all nested subdirectories, including.git/worktrees/<name>/:Fix 2: Special-Case
.git/worktrees/DirectoryAdd explicit handling for Git linked worktree metadata paths:
Fix 3: Use
--add-dirwith Recursive FlagIf the sandbox supports recursive directory permissions, ensure
--add-diris treated as recursive:Fix 4: Fallback to Landlock Path Under-Approximation
As a defensive measure, when Git operations fail with EROFS in a linked worktree, retry with expanded Landlock permissions:
📋 Implementation Priority
| Priority | Fix | Effort | Impact |
|----------|-----|--------|--------|
| P0 | Fix 1: Landlock path propagation | Medium | Core fix for the issue |
| P0 | Fix 2: Special-case .git/worktrees/ | Low | Targeted fix |
| P1 | Fix 3: Recursive --add-dir | Low | Prevents similar issues |
| P2 | Fix 4: Fallback mechanism | Medium | Defensive improvement |
✅ Verification
git addshould succeed in linked worktree💰 Value Assessment
+1 from Codex on macOS in an sf-managed linked worktree on 2026-07-10. The worktree root was writable, but its per-worktree Git directory lived under the parent checkout’s
.git/worktrees/directory. The first fetch failed:The same command succeeded with escalated filesystem access. Staging, committing, checkout, merge, and linked-worktree ref updates required the same broader access boundary. This reproduces the issue for more than
git add: normal Git lifecycle operations in the linked worktree cannot update their shared metadata underworkspace-write.Additional macOS Desktop automation reproduction (2026-07-14)
This remains reproducible in a recurring Codex Desktop automation using a linked Git worktree.
Environment
26.707.71524(bundle5263)0.144.326.5.2(25F84), Apple Siliconworkspace-writetask profileon-requestwith automatic reviewScenario
The automation is intentionally Git-mutating: it starts by fetching
origin, compares a detachedorigin/mainbaseline, and may later create a branch, commit, push, and open a PR.The task workspace is a linked worktree. Its visible
.gitfile resolves outside the workspace:The generated task permission profile exposed the worktree itself as writable and the resolved linked-worktree Git metadata as read-only. In the initial automation turn, the parent
<main-repo>/.gitpath was also nominally writable, but the more-specific read-only linked-worktree entry still won.Failure
The first required command failed before any network work or quality checks:
FETCH_HEADdid not already exist, so Git was attempting to create it. The target directory is owned by the current user with normaldrwxr-xr-xpermissions. Read-only Git operations such asgit status,git log, andgit rev-parsework.Retrying the exact command with
sandbox_permissions: "require_escalated"did not reach an approval that could unblock it. Automatic review rejected the escalation because the managed environment forbade unsandboxed execution.Impact
The unattended quality-gate automation stopped in phase 1. It could not establish the required
origin/mainbaseline, so no Ruff/type checks, autofix PR, or triage issue could be produced.Expected behavior
For an explicitly Git-mutating managed task in a trusted linked worktree, Codex should resolve and grant scoped write access to both:
.git/worktrees/<worktree>.A narrower generated read-only entry should not override the task's explicit Git authorization. If the sandbox cannot safely grant that scope, the escalation path should surface and honor an approval rather than leaving the automation permanently blocked.
Related: #14338 (writable gitdir), #15310 (automation sandbox propagation), and #32848 (nested Code Mode escalation on macOS).