Bash tool: ~/.claude is bind-mounted read-only with no way to opt out, so hook state and config-manager writes always fail with EROFS

Status Open
Reported on v2.1.236
Maintainer reply None cached
Activity 0 comments · opened Sep 1, 2026

Summary

On Linux, the Bash tool runs in a mount namespace where ~/.claude, ~/.claude.json
and each trusted repo's .claude/ are bind-mounted read-only. Every write from Bash
into those paths therefore fails with EROFS, and there is no supported way to opt out:

  • "sandbox": { "enabled": false } in ~/.claude/settings.json does not remove it.
  • The Bash tool's dangerouslyDisableSandbox: true does not remove it.

Meanwhile the Write and Edit tools write to the same paths without any trouble, so this
is not a policy boundary — it only blocks one of the two tool paths. That asymmetry is what
makes it costly: the restriction is invisible until a command fails, and the failure surfaces
as a bare EROFS with no mention of a mount.

Evidence

Claude Code 2.1.236, native build, Linux 5.15 (Ubuntu), no managed settings.

From inside a Bash tool call:

$ grep -i claude /proc/self/mountinfo
... /home/USER/.claude/debug   /home/USER/.claude/debug   rw,nosuid,nodev,relatime ...
... /home/USER/.claude/ide     /home/USER/.claude/ide     rw,nosuid,nodev,relatime ... tmpfs
... /home/USER/.claude         /home/USER/.claude         ro,nosuid,nodev,relatime ...
... /home/USER/.claude.json    /home/USER/.claude.json    ro,nosuid,nodev,relatime ...
... /home/USER/<repo>/.claude  /home/USER/<repo>/.claude  ro,nosuid,nodev,relatime ...

~/.claude/debug and ~/.claude/ide are rw submounts; everything else under ~/.claude is ro.

Writing there fails identically with and without the sandbox override:

$ chezmoi apply ~/.claude/settings.json
chezmoi: .claude/settings.json: open /home/USER/.claude/.settings.jsonNNNNNNNN: read-only file system
# exit 1 — same result with dangerouslyDisableSandbox: true

The same one-line change applied through the Edit tool succeeded on the first try, and the
file on disk reflected it.

Impact

  1. Hooks that persist their own state cannot be invoked from Bash. A PreToolUse gate that

records "this was reviewed / this ticket was transitioned" under ~/.claude/<tool>/state/
works when the hook itself runs (Claude Code's own process), but the companion CLI that the
agent is supposed to run to write the marker fails every time. Users hit this as a hard
wall with no hint about the cause.

  1. chezmoi apply (and any config manager) can never target ~/.claude from Bash, so

declaratively-managed Claude configs need an out-of-band manual step on every change.

  1. Auto mode actively steers into it. While auto mode is active the agent is instructed to

prefer sed/heredocs over the Write and Edit tools for file changes — precisely the path
that cannot work for these paths. The result is a repeating try → EROFS → switch-to-Edit
round trip, several times per session.

What would help (any one of these)

  • Document the mount and expose a supported, writable location for hook/CLI state (an

XDG_STATE_HOME-style path, or making ~/.claude/state an rw submount like debug/ide).

  • Honor the existing escape hatches: either sandbox.enabled: false or

dangerouslyDisableSandbox: true lifting the config-dir bind mount would be unsurprising,
given both already read as "turn this protection off".

  • At minimum, fail with a message that names the cause — e.g. "~/.claude is mounted

read-only for Bash; use the Write/Edit tools" — instead of a raw EROFS that gives the agent
nothing to act on.

Related but distinct: #78162 is the same error text from one-hop symlink resolution during
Claude Code's own atomic settings write, not from the Bash mount namespace.

View original on GitHub ↗