preview_start: spawned children die with EPERM (uv_cwd / file open) for projects under Desktop paths with spaces — Bash tool works in same dir
Summary
preview_start (Claude Preview MCP / Launch panel in the desktop app) cannot start any dev server for a project located under ~/Desktop in a path containing spaces. Every spawned child process dies instantly with EPERM, before the server command even runs. The Bash tool reads/writes the same directory without issues in the same session, so the block is specific to how the preview daemon spawns/sandboxes its children.
Environment
- Claude desktop app (macOS), Claude Code 2.1.197 (
~/Library/Application Support/Claude/claude-code/2.1.197/) - macOS Darwin 25.2.0
- Preview daemon child node: v25.8.1
- Project path (structure matters):
/Users/<user>/Desktop/Folder One/Folder Two/Folder Three/my-project— under Desktop, multiple folder names containing spaces (real names redacted)
Repro
.claude/launch.json:
{
"version": "0.0.1",
"configurations": [
{
"name": "my-project",
"runtimeExecutable": "./node_modules/.bin/vite",
"runtimeArgs": ["--port", "5183", "--strictPort"],
"port": 5183
}
]
}
Call preview_start → fails in <1s:
Error: EPERM: process.cwd failed with error operation not permitted, uv_cwd
at process.wrappedCwd [as cwd] (node:internal/bootstrap/switches/does_own_process_state:142:28)
at node:path:1236:24
at Object.resolve (node:path:1270:19)
at resolveMainPath (node:internal/modules/run_main:35:36)
The child cannot resolve its own working directory at node bootstrap.
Differential test (the informative one)
Changing runtimeExecutable to the absolute path of the vite binary gets the child past cwd resolution, and it then fails reading the entry file itself:
Error: EPERM: operation not permitted, open '/Users/<user>/Desktop/Folder One/Folder Two/Folder Three/my-project/node_modules/vite/bin/vite.js'
at Object.readFileSync (node:fs:436:20)
So the spawned process cannot read anything under the project path — not a cwd-inheritance problem alone.
Ruled out
- macOS TCC / privacy settings: reproduced identically on a fresh app launch (main app process ~3 minutes old, verified via
ps lstart) with Full Disk Access granted to the Claude app. - Stale daemon state: same failure with a brand-new app process tree.
- Port conflicts / launch.json syntax: the same config's command line runs fine via the Bash tool (
./node_modules/.bin/vite --port 5183 --strictPortin the project dir), and the served app works. - Adding
"cwd"to the launch configuration has no effect (field appears to be ignored).
Analysis / suspicion
In the same session, the Bash tool (sandboxed) has full access to this directory, while the preview daemon's children have none. The app launches its worker processes via the Claude.app/Contents/Helpers/disclaimer wrapper; it looks like the sandbox profile applied to preview-daemon children fails to grant the project path. Prime suspects: spaces in the path breaking the profile's path matching, and/or special handling of ~/Desktop.
Impact / workaround
preview_start and the whole preview panel are unusable for such projects. Workaround: run the dev server through the Bash tool and verify via browser MCP tools instead.
---
🤖 Filed with Claude Code on the user's behalf after joint diagnosis.