preview_start named launch.json server fails with getcwd EPERM despite confirmed Full Disk Access
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
- In a project under
~/Documents/<subfolder>/<project>, add a.claude/launch.jsonentry, e.g.:
{
"name": "dashboard",
"runtimeExecutable": "bash",
"runtimeArgs": ["-c", "cd \"<path under ~/Documents>\" && exec python3 <script>.py"],
"port": 8752
}
- Call
preview_start({name: "dashboard"}). - 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
cdtarget that doesn't exist (fails at shell-init before thecdeven 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 isSystem Policy(TCC) against the specific spawnedbash/python3child PIDs at the moment of the failedpreview_startcall -- not a Seatbelt/App-SandboxSandbox: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.