Sandbox: bwrap fails when auto-generated .env deny path resolves through symlink into read-only /nix/store
Summary
Every sandboxed Bash command fails at bwrap setup when the auto-generated secret-protection deny list contains a path that resolves through a symlink into the read-only Nix store.
Environment
- Claude Code 2.1.228, native sandbox (bwrap)
- NixOS, repo using a Nix flake with nix-direnv
Repro
- A flake repo managed by nix-direnv keeps flake-input GC roots as symlinks:
.direnv/flake-inputs/<hash>-source -> /nix/store/<hash>-source. One of these is a store copy of the repo itself (the flakeselfsource). - The repo tracks a
.env.examplefile, so the store copy contains.env.exampletoo. - Claude Code's automatic secret-protection scan adds a read-deny entry for
.direnv/flake-inputs/<hash>-source/.env.example(alongside the working-tree.env.exampleentry). - Every Bash tool call then fails before the command runs:
bwrap: Can't create file at /home/<user>/dev/<repo>/.direnv/flake-inputs/<hash>-source/.env.example: No such file or directory
The store path and the file both exist on the host. The mask fails because the path resolves into the read-only /nix/store, where bwrap cannot create the mask target.
Workarounds tried
- Removing the
.direnv/flake-inputs/<hash>-sourcesymlink unblocks the sandbox immediately. But nix recreates the GC root on the next evaluation (with a new hash after any source change), so the sandbox breaks again in the next session. direnv reloaddoes not help; the store path was never missing.- Per-command sandbox bypass works but defeats the sandbox.
Expected
The deny-mask setup should tolerate paths that resolve into read-only mounts (or mask without following symlinks, or skip the entry with a warning) instead of failing the entire sandbox for every command.
Impact
The sandbox is unusable in any nix-direnv repo whose flake source contains a tracked .env* file. This is a common setup on NixOS.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗