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.
This issue has 13 comments on GitHub. Read the full discussion on GitHub ↗