preview_start named launch.json server fails with getcwd EPERM despite confirmed Full Disk Access

Status Open
Maintainer reply None cached
Activity 0 comments · opened Sep 12, 2026

Description

A .claude/launch.json "named" dev-server configuration (preview_start({name: "..."})) fails to start whenever its working directory is under ~/Documents/..., even though the desktop app (com.anthropic.claudefordesktop) has been confirmed via the system TCC database to hold Full Disk Access.

Reproduction

  1. In a project under ~/Documents/<subfolder>/<project>, add a .claude/launch.json entry, e.g.:
{
  "name": "dashboard",
  "runtimeExecutable": "bash",
  "runtimeArgs": ["-c", "cd \"<path under ~/Documents>\" && exec python3 <script>.py"],
  "port": 8752
}
  1. Call preview_start({name: "dashboard"}).
  2. Observe failure:
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
chdir: error retrieving current directory: getcwd: cannot access parent directories: Operation not permitted
<python3>: can't open file '<script>.py': [Errno 1] Operation not permitted

What we ruled out

  • Directory/file permissions on the target path: normal, verified via ls -la/stat.
  • Not an iCloud/FileProvider-backed path: confirmed via df/mount, plain local APFS volume.
  • Not a stale/missing target directory: reproduced identically even against a cd target that doesn't exist (fails at shell-init before the cd even runs).
  • Not missing Full Disk Access: confirmed via the macOS TCC database itself:

kTCCServiceSystemPolicyAllFiles|com.anthropic.claudefordesktop|2 (auth_value 2 = granted), verified AFTER a full quit+relaunch of the app.

  • The unified log (log show --predicate '...deny(1)...') shows the denial is System Policy (TCC) against the specific spawned bash/python3 child PIDs at the moment of the failed preview_start call -- not a Seatbelt/App-Sandbox Sandbox: denial, not a plain Unix EACCES.
  • A completely separate mechanism -- Bash-tool-spawned processes (a different Anthropic bundle id, com.anthropic.claude-code, used for direct tool calls) -- can read/write/execute in the exact same directory with no issue at all, at the same time.

Suspected cause

The child processes spawned by preview_start's named-config path (bash -> python3) don't appear to inherit com.anthropic.claudefordesktop's TCC identity when the kernel evaluates them, even though the app itself holds Full Disk Access. This is consistent with a broken "responsible process" attribution somewhere in how those children are forked/exec'd.

Environment

  • macOS (Darwin 25.6.0)
  • Claude for Desktop app version 1.52386.3
  • Full Disk Access confirmed via system TCC.db query as described above

Workaround

Start the dev server directly via a Bash tool call, then use preview_start({url: "http://localhost:<port>"}) instead of the name: config -- this avoids the affected spawn path entirely and works reliably.

View original on GitHub ↗