[BUG] Sandbox fails on macOS Tahoe (darwin25): zsh 5.9 accesses hw.* sysctls not whitelisted in sandbox profile
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?
Enabling sandbox.enabled: true in settings causes all Bash tool calls to fail with Sandbox failed to initialize. on macOS Tahoe (macOS 26, darwin25). The root cause has been identified through sandbox profile analysis: zsh 5.9 (arm64-apple-darwin25) reads hw.* sysctls at startup that are not in Claude Code's seatbelt profile allowlist, causing zsh initialization to fail inside the sandbox.
This is a regression specific to macOS Tahoe — the profile worked on macOS Sequoia (darwin24).
Environment:
- Claude Code: 2.1.92
- macOS: 26.4.1 (darwin 25.4.0), Apple Silicon (arm64)
- Shell: zsh 5.9 (arm64-apple-darwin25.0)
- sandbox-exec itself works: sandbox-exec -p '(version 1)(allow default)' /bin/echo OK → OK
Note: Issue #26095 reported the same symptom but was closed without root cause analysis.
What Should Happen?
Sandbox works out of the box on macOS Tahoe (darwin25).
Error Messages/Logs
Steps to Reproduce
- macOS 26 Tahoe (darwin25), Apple Silicon
- Set in ~/.claude/settings.json
{
"sandbox": { "enabled": true, "failIfUnavailable": false }
}
- Run any Bash command via the Claude Code Bash tool
- Result: Sandbox failed to initialize.
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.92
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
Root cause
The macOS sandbox profile in Claude Code 2.1.92 (Zx4() function) allows only specific sysctl-name entries and the prefix hw.optional.arm. On macOS Tahoe, zsh 5.9 reads additional hw.* sysctls at initialization (e.g. hw.targettype, hw.osenvironment, hw.features.allows_security_research, hw.jetsam_properties_product_type and others) that are denied by the profile's (deny default ...) rule.
Proof via manual sandbox-exec testing:
# FAILS - Claude Code's profile with specific hw.* entries:
sandbox-exec -f claude_profile.sb /bin/zsh -c 'echo test'
# → Exit 1
# WORKS - same profile + (sysctl-name-prefix "hw."):
sandbox-exec -f claude_profile_with_hw_prefix.sb /bin/zsh -c 'echo test'
# → Exit 0
# WORKS - bash never needed the missing hw.* sysctls:
sandbox-exec -f claude_profile.sb /bin/bash -c 'echo test'
# → Exit 0
The (allow sysctl-read) block in the profile needs to be expanded:
- (sysctl-name-prefix "hw.optional.arm")
+ (sysctl-name-prefix "hw.")
or more conservatively, add the specific names zsh 5.9/darwin25 needs.
Workaround
Force Claude Code to use bash instead of zsh by adding to ~/.claude/settings.json:
{
"sandbox": {
"enabled": true,
"failIfUnavailable": false
},
"env": {
"CLAUDE_CODE_SHELL": "/bin/bash"
}
}
bash does not access the additional hw.* sysctls and works correctly inside the sandbox.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗