[BUG] preview_start always fails on Windows desktop app with "cwd must be a relative path within the project root"

Resolved 💬 3 comments Opened Apr 17, 2026 by DevEnchanter Closed May 26, 2026

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 startFromConfigjTt). 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 from sessionCwd / i.cwd) is stored with forward slashes: C:/Users/<me>/projects/<repo>. Visible in %APPDATA%\Claude\logs\main.log as LocalSessions.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.sep on Windows is \.
  • "C:\Users\...\apps\web".startsWith("C:/Users/.../<repo>" + "\\") is always false.
  • i !== A is 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 the jTt function.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗