[Bug] v2.1.117 regression: parallel Bash tool calls corrupt fd 3 in nested-Docker sandbox; permanent /proc/self/fd/3: Permission denied

Status Fixed / completed
Reported on v2.1.117
Maintainer reply None cached
Activity 10 comments · opened Apr 22, 2026 · closed Apr 23, 2026

Summary

In Claude Code 2.1.117, when running claude -p "..." inside a Docker container with the per-Bash sandbox enabled, multiple Bash tool calls issued in parallel within a single turn corrupt file descriptor 3 in the inner sandbox wrapper. The first parallel call fails:

Exit code 126
/bin/bash: line 4: /proc/self/fd/3: Permission denied

Other parallel calls in the same turn are cancelled by Claude as "parallel tool call errored". Every subsequent Bash call in the session — including a trivial echo "test" — also fails with the same fd/3 error, permanently disabling the Bash tool. Other tools (Read, Edit, Glob, Grep, Agent, MCP) keep working.

Sequential Bash works. Multiple Reads/Globs/MCP calls in parallel work. Bug is specific to parallel Bash + the inner per-Bash sandbox wrapper.

Pinning to 2.1.116 makes the bug disappear. Same Docker image, same sandbox-settings.json, only the CLI version differs.

Versions

  • Affected: 2.1.117 (released 2026-04-22 00:04 UTC)
  • Last known-good: 2.1.116 (released 2026-04-20)
  • Platform tested: Linux arm64 inside Docker; Docker Desktop on macOS Apple Silicon host. Not tested on bare Linux.

Reproduction

1. Build a minimal image

Dockerfile:

FROM node:20-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl ca-certificates bash bubblewrap socat \
    && rm -rf /var/lib/apt/lists/*
RUN curl -fsSL https://claude.ai/install.sh | bash
ENV PATH="/root/.local/bin:$PATH"
docker build -t fd3-repro .

2. Sandbox config

sandbox-settings.json:

{
  "sandbox": {
    "enabled": true,
    "enableWeakerNestedSandbox": true,
    "failIfUnavailable": true,
    "autoAllowBashIfSandboxed": true,
    "allowUnsandboxedCommands": false,
    "network": {"allowedDomains": []},
    "filesystem": {"allowWrite": ["/tmp"]}
  }
}

(enableWeakerNestedSandbox: true is required inside Docker — without it, bwrap fails with Creating new namespace failed: Operation not permitted.)

3. Run

docker run --rm \
  --cap-add NET_ADMIN --security-opt seccomp=unconfined \
  -v "$PWD/sandbox-settings.json:/sandbox-settings.json:ro" \
  -e CLAUDE_CODE_OAUTH_TOKEN=<your-token> \
  fd3-repro \
  claude -p 'TURN 1: Run ONE Bash call: { echo hello | sed "s/./X/g" ; echo world 2>/dev/null ; }
TURN 2: In ONE response, issue FOUR parallel Bash tool calls — all four at once, not sequentially:
  a) echo first
  b) echo second
  c) echo third
  d) echo fourth
TURN 3: Run: echo after_parallel
Report each result verbatim.' \
    --output-format stream-json \
    --permission-mode dontAsk \
    --allowed-tools Bash \
    --settings /sandbox-settings.json

(The Bash commands inside don't need network — I switched the parallel batch from curl to echo so the repro doesn't depend on any reachable host. The bug fires inside the sandbox wrapper before the user command runs.)

Observed

  • TURN 1 (single complex Bash): ✅ succeeds — output XXXXX\nworld
  • TURN 2 (4 parallel echoes): ❌ first fails with Exit code 126 / /bin/bash: line 4: /proc/self/fd/3: Permission denied. Other 3 cancelled as "parallel tool call errored".
  • TURN 3 (echo after_parallel): ❌ same fd/3 error.

Expected

All 4 parallel Bash calls execute (or are queued); TURN 3 runs cleanly.

What I haven't isolated

  • Whether the prior single Bash in TURN 1 is necessary, or whether the bug also fires on the very first parallel batch with no prior Bash. A separate test with 3 parallel Bash calls and no prior Bash passed (no fd/3 error). So it could be the count threshold (≥4), the prior Bash, an interaction with the specific commands, or timing. Filing what I've reproduced deterministically.

Workaround

RUN curl -fsSL https://claude.ai/install.sh | bash -s -- 2.1.116

Possibly related

  • 2.1.113 introduced the switch from "bundled JS" to "native Claude Code binary" per its release notes. The native binary's sandbox wrapper appears to open /proc/self/fd/3 for some control channel; 2.1.117 is the first version where parallel Bash + the nested-Docker sandbox combine pathologically.
  • #47909 — gradual fd leak in long macOS sessions. Different surface (gradual, macOS, not parallel-triggered) but same general fd-management area.

View original on GitHub ↗

10 Comments

yapus · 4 months ago

Confirming the same regression on bare Linux (no Docker, no nested sandbox), so this isn't Docker-specific.

  • CC: 2.1.117
  • Kernel: Linux 6.18.9 (Arch)
  • bubblewrap: 0.11.1
  • kernel.unprivileged_userns_clone = 1
  • kernel.apparmor_restrict_unprivileged_userns sysctl does not exist (no AppArmor userns restriction)
  • Sandbox config (project settings.local.json):
  "sandbox": {
    "enabled": true,
    "autoAllowBashIfSandboxed": true,
    "allowUnsandboxedCommands": true,
    "excludedCommands": ["./dock *"]
  }

Every sandboxed Bash call fails with the same error you reported, exit 126:
/usr/bin/bash: line 4: /proc/self/fd/3: Permission denied
Trivial reproducers fail immediately:

  • echo hello
  • /bin/echo sandboxed-test

Differences from the original repro

  • No parallelism required. First Bash of the session fails. No prior turn, no batch.
  • No Docker, no enableWeakerNestedSandbox.
  • The fault appears tied to the wrapper's fd‑3 output channel. A Bash call that writes only to stderr (echo "$0 $$" 1>&2) succeeds and reports bash PID 2 (so bwrap is launching bash correctly inside a PID namespace).

Commands that write to stdout — which presumably go through the wrapper's /proc/self/fd/3 capture — fail at line 4 of the wrapper.

Effect on agent behavior

Once Bash starts failing, sub‑agents fall back to dangerouslyDisableSandbox: true and the user is prompted for every command — autoAllowBashIfSandboxed: true provides no benefit because nothing runs sandboxed.

solalatus · 4 months ago

Bare linux also, sadly I can also confirm.

SimonAlfie · 4 months ago

Confirmed on Ubuntu 20.04 too.
Platform: Linux (Ubuntu 24.04)
Claude Code version: (2.1.117)

## Behaviour

In a Claude Code session with the sandbox enabled, the first Bash tool call succeeds. All subsequent Bash tool calls fail with:

Exit code 126
/bin/bash: line 3: /proc/self/fd/3: Permission denied

This affects all commands, not just specific tools like git. Even ls fails on the second call.

Adding /proc/self/fd/3 to sandbox.filesystem.allowWrite in settings.json has no effect

I found that several "quick" commands like ls can be run a few times before it fails. 2 or 3 times with no delay for Claude to process the response.

Very irritating! Please fix ASAP! This has really **** me over.

pkrDan · 4 months ago

I am experiencing the same issue on WSL2 using the sandbox tool in Claude Code

kerneltoast · 4 months ago

Same issue over here on Linux, not even using docker or anything, just with /sandbox enabled. Reverting to v2.1.116 indeed fixes it.

widefox · 4 months ago

Confirmed on bare Linux 7.1rc0 . Claude Code version: v2.1.117 regression, works in v2.1.116

Logopher · 4 months ago

Cross-platform confirmation: the same bug also reproduces on Fedora 43 with zsh (#51865) and on WSL2 with bash (#52118). All three: identical exit-126 / line-4 / /proc/self/fd/3: Permission denied signature, all on 2.1.117, all clean on 2.1.116.

The "sequential Bash works; parallel Bash triggers it" framing in this issue matches the WSL2 reproduction — 2.1.117 broke on the 4th parallel call. Once the failure starts in a session, it persists; even bare true fails. Process restart, machine reboot, and the prompt !cmd prefix do not help.

Consolidated investigation with a kernel-mechanism hypothesis — bubblewrap clears the process's PR_SET_DUMPABLE flag (via user namespace, capability drop, or setuid transition), which makes /proc/<pid>/fd/N owned by root and unreadable to the shell's uid; the wrapper's /proc/self/fd/3 open returns EACCES, shell exits 126 — is at https://github.com/anthropics/claude-code/issues/52118#issuecomment-4300143469 .

bwrap as the sandbox technology is established by #51126, a related-but-distinct bug in the same layer.

nobuhiro-sasaki · 4 months ago

Still reproducing on v2.1.118 (current latest). This isn't fixed in 2.1.118.

Env: WSL2 Ubuntu 24.04.3 (kernel 6.6.87), bash, native installer (~/.local/bin/claude → versions/2.1.118).
Symptom: identical — exit 126, /bin/bash: line 4: /proc/self/fd/3: Permission denied, permanent-for-session once triggered.
Trigger observed in my sessions: appears after Interrupt (Escape) on a running Bash call, in addition to the parallel-Bash-call trigger already documented above. Avoiding Interrupt + using timeouts avoids it; if it hits, only /exit + new session recovers.

Auto-update caveat for anyone trying to pin 2.1.116: on 2.1.118 neither DISABLE_AUTOUPDATER=1 alone nor manual symlink flipping is sufficient — auto-update silently re-promotes the symlink to the newest installed version. The new-in-2.1.118 DISABLE_UPDATES=1 is what actually stops it (in settings.jsonenv). Without that, downgrade silently reverts on the next session.

strace data available: I have a 4.2 MB bundle (cc_diag.tar.gz) of strace output captured during a fresh reproduction on v2.1.117 (WSL2, same environment). Happy to share privately or attach if it would help narrow down which bwrap operation clears PR_SET_DUMPABLE — just let me know how you prefer to receive it.

belalik · 4 months ago

Adding a data point: encountered the 2.1.117 fd/3 break on a WSL2 Ubuntu (Win11 host, bwrap 0.9.0)
machine and pinned back to 2.1.116. Chose not to update our second machine (native Kubuntu 24) on
the inference that the bug would surface there too, the cost of reverting mid-work isn't worth
testing for. For 2.1.118 we stayed pinned on both, based on the missing fd/3 entry in the 2.1.118
changelog plus @nobuhiro-sasaki's 2.1.118 reproduction above. Added DISABLE_UPDATES=1 alongside
DISABLE_AUTOUPDATER=1 (thanks @nobuhiro-sasaki for flagging the pin leak).

Trigger variant worth noting, in case it helps narrow down the mechanism: our session's first 3
sandboxed Bash calls succeeded (inline compounds: hostname && pwd, git fetch, ls ~/projects/...).
The first absolute-path script invocation, a small shell script, then produced the fd/3 error,
and from that moment every subsequent sandboxed Bash call failed, including trivial pwd. No
parallel calls, no Interrupt, no zsh (bash 5.2). That's distinct from the parallel-batch trigger
(OP), first-call-of-session (yapus), and post-Interrupt (nobuhiro-sasaki) variants already reported. Same underlying fd/3 signature though, so likely one root cause with multiple triggers. "Line 4" is CC's wrapper, not the user script (our script's line 4 is a comment).

An Anthropic ack on the thread would be much appreciated. "Avoid parallel Bash + avoid Interrupt + hope shell init doesn't trigger it" isn't a workable workaround for sandbox users day-to-day.

github-actions[bot] · 4 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.