2.1.120: --continue/--resume fails with 'sandbox required but unavailable' even with sandbox.enabled=false (regression vs 2.1.119)

Resolved 💬 13 comments Opened Apr 25, 2026 by safitudo Closed May 17, 2026

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(): 4
  • isSandboxRequired(): 4
  • isSandboxingEnabled(): 50
  • isSandboxEnabledInSettings(): 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: enabled
  • which 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

  1. The actual <reason> returned by getSandboxUnavailableReason() 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?
  2. Honor sandbox.enabled = false consistently on the resume code path (it appears to be honored for fresh and --print invocations but not for --continue/--resume in 2.1.120).
  3. Separately, claude --continue (no prompt) on 2.1.120 errors with No 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 --continue UX is now broken for any session that didn't end mid-deferred-tool.

View original on GitHub ↗

This issue has 13 comments on GitHub. Read the full discussion on GitHub ↗