Sandbox wedges on merged-usr Linux: bwrap "Can't mount tmpfs on /newroot/bin" (regression, works on 2.1.229)

Status Open
Reported on v2.1.232
Maintainer reply None cached
Activity 0 comments · opened Aug 19, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

On a merged-usr Linux host — Debian, Ubuntu, and any distro where /bin, /lib, /lib64, /sbin are symlinks into /usr — claude-code 2.1.232+ cannot set up its OS sandbox. Every Bash tool call dies during sandbox setup, before the command runs:

bwrap: Can't mount tmpfs on /newroot/bin: No such file or directory

The exact directory varies (/bin, /lib64, …) — all merged-usr symlinks. With the sandbox enabled, this makes the Bash tool unusable: every command, including a bare pwd, fails identically. It is independent of the model and the project, and it is a regression — the same host + same sandbox settings work on 2.1.229.

What Should Happen?

The OS sandbox should set up on a merged-usr host and Bash commands should run — as they do on 2.1.229. A merged-usr symlinked system directory (/bin -> usr/bin) should be handled as a symlink (its real target under /usr), not have a tmpfs mounted onto a mount point that does not exist in the new root.

Error Messages/Logs

bwrap: Can't mount tmpfs on /newroot/bin: No such file or directory

(also seen as /newroot/lib64, and as "Read-only file system" when the target sits on a read-only fs)

Steps to Reproduce

Minimal, no specific project or model. A merged-usr base (Debian) + claude-code with the OS sandbox on.

1. Image (Debian trixie is merged-usr: /bin,/lib,/lib64,/sbin -> /usr/*):

FROM debian:trixie-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
      curl ca-certificates bubblewrap socat && rm -rf /var/lib/apt/lists/*
RUN curl -fsSL https://claude.ai/install.sh | bash -s -- 2.1.235 \
 && cp -L /root/.local/bin/claude /usr/local/bin/claude

bubblewrap and socat are both required — without socat claude silently disables the sandbox ("sandbox is enabled but dependencies missing"), so the bug hides.

2. User settings ~/.claude/settings.json enabling the sandbox:

{ "sandbox": { "enabled": true, "enableWeakerNestedSandbox": true,
  "filesystem": { "denyRead": ["/"], "denyWrite": ["/"],
    "allowRead": ["/usr","/etc","/tmp","/w"], "allowWrite": ["/tmp","/w"] } } }

3. Run any Bash tool call as a non-root user, e.g. claude -p "run pwd".
(claude refuses the sandbox bypass as root; the sandbox needs unprivileged user namespaces — on by default on Debian/Ubuntu; inside a restricted container add --privileged or enable userns.)

Result on 2.1.235 — the Bash tool result is:

Exit code 1
bwrap: Can't mount tmpfs on /newroot/bin: No such file or directory

On 2.1.229 (same image, same settings) the command runs normally (verified the sandbox is genuinely active: a non-allowed path is correctly masked).

To reproduce without an API key, point ANTHROPIC_BASE_URL at a ~30-line mock that returns one Bash tool_use — happy to attach it.

Claude Model

_No response_

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

Reproduced on 2.1.235 (broken) and 2.1.229 (works). bubblewrap 0.11.0. Debian trixie (merged-usr). Independent of model and API platform.

Platform

Other

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Non-interactive/CI environment

Additional Information

Root cause (from diffing the bundled sandbox code between 2.1.229 and 2.1.232): 2.1.232 added a symlink-hardening guard, whose strings appear only from 2.1.232 on — [Sandbox Linux] Skipping allowRead restore for symlink pointing outside expected location (plus Dropping ancestor pin with symlink component and Refusing to write through symlink). On merged-usr, /bin,/lib,/lib64,/sbin are symlinks into /usr; the guard stops following/restoring them, and the subsequent --tmpfs mask of the symlinked directory then fails because its mount point does not exist in the new root -> Can't mount tmpfs on /newroot/<dir>.

Suggested fix: treat a merged-usr symlink whose real target is already inside a granted tree (/bin -> usr/bin while /usr is readable) as its target, rather than dropping the symlink and masking a path that was never created.

Related: #87935 (sandbox setup failing when the working directory is on a read-only filesystem) — same "sandbox setup mishandles the host's filesystem layout" area, different trigger (merged-usr symlinks vs a read-only mount).

View original on GitHub ↗