preview_start fails with spawn disclaimer ENOENT on macOS 26.2 (embedded claude-code 2.1.111)
Summary
mcp__Claude_Preview__preview_start consistently fails with:
spawn /Applications/Claude.app/Contents/Helpers/disclaimer ENOENT
…even though that binary exists, is correctly codesigned, and runs fine when invoked directly from a shell. Reproducible across every .claude/launch.json config I've tried (python3, npx, npm), regardless of whether runtimeExecutable is a PATH-resolved command or an absolute path, regardless of cwd.
Environment
- macOS: 26.2 (25C56), arm64
- Claude Desktop: 1.3883.0
- Embedded claude-code bundle: 2.1.111 (at
~/Library/Application Support/Claude/claude-code/2.1.111/) - Native claude-code CLI: 2.1.119 (at
~/.local/bin/claude, separate install, not what's running here —CLAUDE_CODE_ENTRYPOINT=claude-desktop)
Reproduction
Any .claude/launch.json entry will do. Example:
{
"name": "static-server",
"runtimeExecutable": "/opt/homebrew/bin/python3",
"runtimeArgs": ["-m", "http.server", "4545"],
"port": 4545,
"cwd": "."
}
Call preview_start → ENOENT.
Diagnostics gathered
disclaimer binary is healthy:
- Exists:
-rwxr-xr-x 135600 bytesat/Applications/Claude.app/Contents/Helpers/disclaimer file:Mach-O universal binary with 2 architectures: [x86_64] [arm64]codesign -dvvv: signed by Anthropic PBC (TeamQ6L2SF6YDW), hardened runtime enabled,Developer ID Applicationcert, Apple-timestamped 2026-04-21.otool -L: only dep is/usr/lib/libSystem.B.dylib- Direct exec works:
disclaimer /bin/echo hello→hello xattr: onlycom.apple.provenance/com.apple.macl— nothing quarantine-related
Claude Desktop / Claude Code entitlements:
Neither has com.apple.security.app-sandbox. Claude Code's entitlements are just cs.allow-jit, cs.allow-unsigned-executable-memory, cs.disable-library-validation, device.audio-input. So classic App Sandbox denial is out.
Possibly related (but not the root cause): the embedded claude.app bundle at ~/Library/Application Support/Claude/claude-code/2.1.111/claude.app/Contents/ ships without a Helpers/ subdirectory:
Contents/
├── CodeResources
├── Info.plist
├── MacOS
└── _CodeSignature ← no Helpers/
Deleting the 2.1.111/ directory and letting Claude Desktop re-download produces the same bundle layout. Symlinking /Applications/Claude.app/Contents/Helpers into the embedded bundle at Contents/Helpers does not change the preview_start error — preview_start already hardcodes the absolute /Applications/Claude.app/... path, so the embedded Helpers absence is likely a red herring.
Why it looks like a sandbox-masked denial
ENOENT on spawn() when the file demonstrably exists, is executable, and is invokable from a normal shell is the classic fingerprint of macOS kernel-level exec denial (TCC, sandbox, or entitlement mismatch) — macOS masks the real error as ENOENT. But none of the visible entitlements explain which policy would be denying it.
What I'd expect the fix to look like
Either:
preview_startshouldn't be spawning via the desktop-app-bundledisclaimerat all from the embedded claude-code — it should use a helper bundled alongside the claude-code binary (which means shippingHelpers/inside the embedded bundle).- Or the disclaimer call path needs an env/entitlement adjustment so the cross-bundle exec actually resolves.
Workaround
For pre-commit visual spot-checks, dropping to bash + python3 -m http.server on a temp fixture dir + manual browser load. Works but loses preview_screenshot / preview_inspect.
Happy to share more
launch.json content, full error traces, codesign dumps, dtruss of a failing spawn, etc. Let me know what would help.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗