[BUG] preview_start always fails on Windows desktop app with "cwd must be a relative path within the project root"
Environment
- OS: Windows 11 (x64)
- Claude Code Desktop:
1.3109.0.0(MSIX,C:\Program Files\WindowsApps\Claude_1.3109.0.0_x64__pzs8sxrjxfjjc) - Shell used to launch: Desktop app + PowerShell (not Git Bash / WSL)
- Node (MCP embedded): default shipped in app
Summary
preview_start fails unconditionally on the Windows desktop app for every launch.json configuration — regardless of cwd value, runtimeExecutable, program, or port. The error:
Failed to start server: cwd must be a relative path within the project root.
…is thrown before any child process is spawned, so the spawn npm ENOENT Windows workaround discussed in #27459 never applies.
Repro
Any Windows desktop session with any .claude/launch.json, e.g. the exact monorepo example from https://code.claude.com/docs/en/desktop#configure-preview-servers:
{
"version": "0.0.1",
"configurations": [
{
"name": "web",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["dev"],
"cwd": "apps/web",
"port": 3000
}
]
}
Call preview_start (via MCP tool call or the Preview-dropdown "Start server" UI — both code paths call startFromConfig → jTt). Result: same error, every time.
Tested across every permutation: cwd: "apps/web", cwd: ".", cwd: "${workspaceFolder}/apps/web", no cwd field, runtimeExecutable = pnpm/npm/npx/node, using program instead of runtimeExecutable, different ports — all produce the identical error.
Root cause
The validation in the jTt function in app.asar\.vite\build\index.js (line ~672):
const i = ae.resolve(A, t.cwd); // ae = require("path")
if (i !== A && !i.startsWith(A + ae.sep))
throw new Error("cwd must be a relative path within the project root.");
A(project root, derived fromsessionCwd/i.cwd) is stored with forward slashes:C:/Users/<me>/projects/<repo>. Visible in%APPDATA%\Claude\logs\main.logasLocalSessions.getPrStateForBranch: cwd=C:/Users/<me>/projects/<repo>.- On Windows,
path.resolve(A, "apps/web")always returns a backslash-normalized path:C:\Users\<me>\projects\<repo>\apps\web. path.sepon Windows is\."C:\Users\...\apps\web".startsWith("C:/Users/.../<repo>" + "\\")is always false.i !== Ais also always true because of the slash-direction mismatch.- → validation throws unconditionally.
This is not environment-specific. The app does path normalization to forward slashes in ~38 places (greppable replace(/\/g, "/") in the minified bundle), so the forward-slash A is reached via internal code, not user input.
Stack trace (from main.log)
[Preview] startFromConfig failed: {
error: Error: cwd must be a relative path within the project root.
at jTt (C:\Program Files\WindowsApps\Claude_1.3109.0.0_x64__pzs8sxrjxfjjc\app\resources\app.asar\.vite\build\index.js:672:749)
at Object.startFromConfig (...\app.asar\.vite\build\index.js:6861:16366)
at async ...\app.asar\.vite\build\index.js:43:418916
at async Session.<anonymous> (node:electron/js2c/browser_init:2:116462)
}
Proposed fix (one line)
Normalize A before the check so both sides use the same separator direction:
const A_n = ae.normalize(A); // or A.split("/").join(ae.sep)
const i = ae.resolve(A_n, t.cwd);
if (i !== A_n && !i.startsWith(A_n + ae.sep))
throw new Error("cwd must be a relative path within the project root.");
Or normalize sessionCwd to the platform separator at session creation (preferred — addresses the root cause rather than the symptom).
Expected behavior
preview_start launches the configured dev server and returns a serverId — matching the documented behavior and the behavior on macOS/Linux.
Notes
- Bash workaround works (manually start the dev server in a terminal, use browser) — but it bypasses the embedded preview pane and all the
preview_*inspection tools. - Searching GitHub issues and the web for the exact error string
"cwd must be a relative path within the project root"returns zero hits, suggesting this may be a recent regression — worth bisecting recent changes to the Preview/MCP layer around thejTtfunction.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗