2.1.120: --continue/--resume fails with 'sandbox required but unavailable' even with sandbox.enabled=false (regression vs 2.1.119)
Summary
On macOS, Claude Code 2.1.120 refuses to start a resumed session, exiting with:
Error: sandbox required but unavailable: <reason>
sandbox.failIfUnavailable is set — refusing to start without a working sandbox.
The same machine on 2.1.119 resumes the same sessions cleanly. Fresh (non-resumed) sessions on 2.1.120 also work — only --continue and --resume are affected.
~/.claude/settings.json already has the documented escape hatch:
"sandbox": {
"enabled": false,
"failIfUnavailable": false
}
…and the error still fires on 2.1.120 resumes. With sandbox.enabled = false, isSandboxRequired() should short-circuit to false in both versions (verified by inspecting the binaries — see below), so the user-facing settings are not actually suppressing the resume-path check in 2.1.120.
Reproduction
# Works on 2.1.120
claude # fresh session, fine
claude --print "hi" # fine
# Fails on 2.1.120
claude --continue # → "No deferred tool marker found ..."
claude --continue "continue" # → sandbox-required error
claude --resume <session-id> "x" # → sandbox-required error
# Same commands on 2.1.119: all work
/path/to/versions/2.1.119 --continue "continue" # OK
Settings file is valid JSON, no managed-settings layer present (/Library/Application Support/ClaudeCode/, ~/Library/Application Support/ClaudeCode/, /etc/claude-code/ all absent), no relevant env vars set, sandbox-exec exists at /usr/bin/sandbox-exec, SIP enabled (default).
What the binaries show
Both 2.1.119 and 2.1.120 have functionally equivalent gates:
// 2.1.120 (minified)
function y7_() { return l8()?.sandbox?.enabled ?? false } // sandbox.enabled
function uc_() { /* platform allowed list — true if no policy restricts */ }
function bZ1() { return y7_() && uc_() && (l8()?.sandbox?.failIfUnavailable ?? false) } // isSandboxRequired
Identical call counts on both versions:
getSandboxUnavailableReason(): 4isSandboxRequired(): 4isSandboxingEnabled(): 50isSandboxEnabledInSettings(): 6
So the gating logic is unchanged. The regression appears to be in when/where the resume code path consults the gate — 2.1.120 surfaces the unavailability before the user's sandbox.enabled = false is honored on resume specifically.
Environment
- Claude Code: 2.1.120 (failing) vs 2.1.119 (working)
- Platform: macOS Darwin 25.2.0, arm64
- Binary:
/Users/<user>/.local/share/claude/versions/2.1.120(Mach-O arm64, Bun-bundled) - Shell: zsh
csrutil: enabledwhich sandbox-exec:/usr/bin/sandbox-exec
Workaround
Pin to 2.1.119:
ln -sf ~/.local/share/claude/versions/2.1.119 ~/.local/bin/claude
Asks
- The actual
<reason>returned bygetSandboxUnavailableReason()on the failing machine would be the most useful next data point — currently the value is truncated in the user-facing error before the line wraps. Could the error printer be tweaked to always print the reason on its own line / not truncate it? - Honor
sandbox.enabled = falseconsistently on the resume code path (it appears to be honored for fresh and--printinvocations but not for--continue/--resumein 2.1.120). - Separately,
claude --continue(no prompt) on 2.1.120 errors withNo deferred tool marker found in the resumed session.whenever the prior session ended cleanly — the message tells you to "Provide a prompt", which works, but the bare--continueUX is now broken for any session that didn't end mid-deferred-tool.
13 Comments
Linux confirmation, plus a stricter variant — we hit this with no
sandboxkey in settings at all, not just with the documented opt-out.Environment
bwrapnot installed (no sandbox backend present)~/.claude/settings.json,~/.claude/settings.local.json, project-level.claude/settings.local.json— none of them contain asandboxkey.isSandboxRequired()should short-circuit on the missing config, the same way 2.1.119 did.Repro
A long-lived session (started 2026-04-18, last real turn 2026-04-24 18:12 UTC, 1635 messages, 5.2 MB transcript) that was idle when the 2.1.120 swap landed. ~30 minutes after the swap:
Output is the unrendered React/JSX dump from #53081, ending with:
On the same binary, same machine, same shell:
So this matches #53085 exactly: only the resume path fails, and it fails on a config that nowhere opts into
failIfUnavailable=true. The sandbox gate appears to be evaluated more aggressively (or with different defaults) on the resume code path than on fresh start.Diff vs. the macOS report
bwrap(no backend, not just disabled backend).sandboxkey in any settings file — so this isn't "the opt-out is being ignored", it's "the implicit default is different on resume vs fresh-start".${j$}is literally unrendered, so on Linux a user with no other context sees a 100+ line minified JSX dump and an unhelpful template-literal placeholder.Severity note
Long-lived sessions (multi-day, multi-MB transcripts) are exactly the ones users most want to resume. A version swap during idle that silently breaks resume-only on those sessions is a high-impact regression: starting a fresh session "works" but throws away the conversation the user wanted back. We were able to recover the last work output by parsing the jsonl directly, but that's not a path most users will know about.
Cross-ref: #53081 (the unrendered
${j$}is from the same code path).+1 — confirming on macOS 26.4.1 (Darwin 25.4.0, arm64), Claude Code 2.1.120 (native install).
Fresh sessions work fine;
claude --resumeandclaude --continueconsistently die with the samesandbox required but unavailable: sandbox.failIfUnavailable is seterror. Adding"sandbox": { "enabled": false, "failIfUnavailable": false }to~/.claude/settings.jsondid not suppress the error, matching the report.No managed-settings layer, no project-level settings, no env overrides,
sandbox-execworks (sandbox-exec -n no-internet /usr/bin/truesucceeds).+1 — confirming on Windows 11 Pro (10.0.26200), Claude Code 2.1.120 (native install).
Same regression: fresh claude works, claude --resume / claude --continue die with sandbox required but unavailable. Downgrading to 2.1.119 resolves it.
Matches @seanssoh stricter variant: no sandbox key anywhere in ~/.claude/settings.json, ~/.claude/settings.local.json, or project-level .claude/settings.local.json. No managed-settings layer (no C:\ProgramData\ClaudeCode\, no C:\Program Files\ClaudeCode\). So this is the "implicit default differs on resume vs fresh-start" path, not the "opt-out is ignored" one.
Different minified placeholder: OP and @seanssoh both show ${j$}. On Windows I get ${j8}:
Error: sandbox required but unavailable: ${j8}
sandbox.failIfUnavailable is set — refusing to start without a working sandbox.
Different minified variable name in the unrendered template literal — likely a different code path or a different build-shape on Windows than the macOS/Linux builds. Worth a look alongside #53081.
Environment
same issue
same issue
+1 same issue
same issue
same issue on MacOS 26.2
same issue on MacOS 26.2
Workaround (without downgrading): Start a new session without
--continueor--resumeand use/resumefrom inside the TUI.Same v2.1.120 regression cluster as #53086 — different surface (sandbox-required error vs
g9H is not a functioncrash) but same--resume/--continuecode path.The two workarounds that work today:
REPL
/resumedoes not hit the broken--resumeflag path, so the sandbox check that fires on the flag is skipped.sandbox.enabled=falsein your config is being overridden somewhere in the v2.1.120--resumeinitialization sequence — separate code path from the v2.1.119 sandbox handling that respected the setting. Workaround until shipped fix lands.This is a duplicate of #53041, which was fixed as of version 2.1.121.
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.