bwrap sandbox crashes on fresh project dirs: 'Can't create file at <cwd>/.claude/settings.json: Read-only file system'

Open 💬 0 comments Opened Jul 13, 2026 by ProtoErikS

Bug description

When starting a Claude Code session with a working directory that has no pre-existing .claude/settings.json, the sandbox (bwrap) crashes on the very first Bash tool call — and continues crashing on every subsequent Bash call — with:

bwrap: Can't create file at <cwd>/.claude/settings.json: Read-only file system

This makes the Bash tool (and by extension most agentic work) completely unusable in any fresh project directory, on this machine, until the issue is worked around manually.

Environment

  • OS: Bazzite (Fedora Atomic / Kinoite base), VERSION="44.20260629.0 (Kinoite)", ID_LIKE="fedora"
  • Kernel: Linux bazzite 7.0.9-ogc3.2.fc44.x86_64
  • claude --version: 2.1.207 (Claude Code)
  • Install method: official curl ... | bash installer (native binary, not Flatpak/toolbox/distrobox)
  • /var/home is a real btrfs subvolume (/dev/nvme0n1p3 on /var/home type btrfs (rw,relatime,...)); /home is a symlink to /var/home (standard on Fedora Atomic/Bazzite/Silverblue-family systems)
  • ~/.claude/settings.json has sandbox.enabled: true, with filesystem.allowRead/allowWrite including the working directory in question (tried both the /home/... symlink form and the canonical /var/home/... form — neither avoided the crash)

Repro steps

  1. On a Fedora Atomic-family system where /home is a symlink to /var/home (or generally: any system), cd into a directory that has never been used as a Claude Code project root (no .claude/ subdirectory, or a .claude/ dir missing some of its expected files).
  2. Start claude there with sandbox.enabled: true in ~/.claude/settings.json.
  3. Run any Bash tool command (even a no-op like echo test).

Observed behavior

The Bash tool fails with a bwrap filesystem error referencing a different missing file each time, in this order, as each preceding one is manually pre-created:

  1. <cwd>/.claude/settings.json
  2. <cwd>/.claude/settings.local.json
  3. <cwd>/.gitconfig

(We stopped after 3 rounds once we had enough to report, but nothing suggests the list is exhaustive — it appears the harness is trying to create a placeholder/stub for each of a set of "protected" or "sandboxed" paths one at a time, and errors out the whole Bash tool call the moment any single one fails to be created, rather than continuing past it or creating them all up front.)

Manually pre-creating each file (empty file, or {} for JSON files) as it's named in the error message allows the next Bash call to proceed further, until it hits the next missing path. This strongly suggests the crash is caused by the harness failing to touch/create these placeholder files — not by an actual read-only filesystem (see below), and not by genuine deny-list enforcement (creating the files unblocks progress, it doesn't get rejected outright).

What we ruled out

  • Not a real read-only filesystem or permissions issue: mount/findmnt/stat on the target directory (run directly in the user's shell, outside the sandbox) confirm it's a normal rw btrfs mount, owned by the invoking user, 0755 permissions.
  • Not a /home vs /var/home symlink path-mismatch in user config: updating ~/.claude/settings.json's sandbox.filesystem.allowRead/allowWrite to use the canonical /var/home/... form (matching the session's actual resolved cwd) had no effect — the crash was identical before and after.
  • Not a nested container/Flatpak/toolbox sandboxing layer: Claude Code was installed via the official native curl | bash installer, running directly on the host with no additional container layer to explain a divergent filesystem view.
  • Not fixable via ~/.claude/settings.json at all: no combination of sandbox.filesystem.allowRead/allowWrite changes resolved it. Setting sandbox.enabled: false is the only workaround found, which disables the OS-level sandbox entirely (losing the bwrap-level enforcement backstop, leaving only the permission-prompt layer).

Impact

Because the specific list of paths the harness wants to pre-create isn't documented (we only discovered each one by hitting the crash, fixing it, and hitting the next), it's impractical to pre-populate a directory before first use — e.g., a freshly-cloned repository the user hasn't opened Claude Code in yet will hit this immediately, with no way to know in advance which files need to be manually created. On this machine, the only viable workaround currently is disabling the sandbox entirely (sandbox.enabled: false), which removes OS-level filesystem/network confinement for all Bash tool calls.

Suggested fix directions

  • The placeholder-creation step for self-protected config paths should tolerate/ignore failures to create a not-yet-existing file (e.g., skip the read-only bind-mount for that specific path if it doesn't exist yet, rather than crashing the entire sandbox setup), OR
  • All placeholder paths should be created/ensured in a single batch before the sandbox mounts are constructed, with clear, actionable error output if any single one fails (rather than surfacing as a bare bwrap error that gives no indication it's an internal harness bootstrap issue), OR
  • Investigate why file creation is failing for a target that is, at the real filesystem level, fully writable — since none of the ruled-out causes above explain the actual EROFS being raised inside the bwrap-constructed mount namespace.

View original on GitHub ↗