Skip to content

fix: buildNpmScriptCommand always uses cmd.exe on Windows#734

Open
jamiechicago312 wants to merge 6 commits into
OpenHands:mainfrom
jamiechicago312:fix/windows-vite-path-spaces
Open

fix: buildNpmScriptCommand always uses cmd.exe on Windows#734
jamiechicago312 wants to merge 6 commits into
OpenHands:mainfrom
jamiechicago312:fix/windows-vite-path-spaces

Conversation

@jamiechicago312
Copy link
Copy Markdown
Member

Problem

npm run dev fails immediately on Windows with:

[vite] 'C:\Program' is not recognized as an internal or external command,
[vite] operable program or batch file.
[vite] Exited with code 1

Vite never starts, and the ingress proxy returns Bad Gateway for every request to localhost:8000. This happens on a clean install — no .env, no special config needed.

Root cause

When npm run dev is executed on Windows, npm sets npm_execpath to something like:

C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js

In buildNpmScriptCommand the npm_execpath branch fires first, returning that full path (with spaces) as a spawn argument, and using process.execPath (C:\Program Files\nodejs\node.exe — also with spaces) as the command.

spawnService uses shell: process.platform === "win32", so Node.js builds the shell command:

cmd.exe /d /s /c C:\Program Files\nodejs\node.exe C:\Program Files\...

cmd.exe splits on the space, sees C:\Program as the command, and fails. The win32 branch in buildNpmScriptCommand already has the correct fix (cmd.exe /d /s /c npm run <script>), but it came after the npm_execpath branch, so it was never reached on Windows when running via npm run dev.

Fix

Move the win32 check before the npm_execpath check. On Windows, we always use:

{ command: env.ComSpec || "cmd.exe", args: ["/d", "/s", "/c", "npm", "run", scriptName] }

This is safe on all Windows Node installs regardless of where npm was installed or whether npm_execpath contains spaces.

No changes needed on macOS or Linux — those platforms continue to use the npm_execpath-aware path.

Testing

  • Added a new regression test that specifically exercises Windows + npm_execpath with spaces (the exact scenario from the bug report).
  • Renamed the previous Windows+npm_execpath test to POSIX since the npm_execpath shortcut only matters on non-Windows platforms.
  • All existing cmd.exe fallback tests continue to pass.

Closes / supersedes #716 (the docs-only workaround).


This PR was created by an AI agent (OpenHands) on behalf of the user.

@jamiechicago312 can click here to continue refining the PR

jamiechicago312 and others added 2 commits May 22, 2026 11:17
On Windows, npm sets npm_execpath to a path like
  C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js
which contains spaces. buildNpmScriptCommand was returning that
path as a spawn argument with the full node.exe path as the command.
spawnService uses shell:true on Windows, so Node.js passes the
unquoted command to cmd.exe:

  cmd.exe /d /s /c C:\Program Files\nodejs\node.exe ...

cmd.exe splits on the space and fails with
  'C:\Program' is not recognized as an internal or external command
causing Vite to exit with code 1 immediately after npm run dev.

Fix: check platform === 'win32' BEFORE checking npm_execpath so
Windows always uses the safe cmd.exe /d /s /c npm run <script> form.

Co-authored-by: openhands <openhands@all-hands.dev>
On Windows, npm sets npm_execpath to a path like
  C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js
which contains spaces. buildNpmScriptCommand was returning that
path as a spawn argument with the full node.exe path as the command.
spawnService uses shell:true on Windows, so Node.js passes the
unquoted command to cmd.exe:

  cmd.exe /d /s /c C:\Program Files\nodejs\node.exe ...

cmd.exe splits on the space and fails with
  'C:\Program' is not recognized as an internal or external command
causing Vite to exit with code 1 immediately after npm run dev.

Fix: check platform === 'win32' BEFORE checking npm_execpath so
Windows always uses the safe cmd.exe /d /s /c npm run <script> form.

Co-authored-by: openhands <openhands@all-hands.dev>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 22, 2026

@jamiechicago312 is attempting to deploy a commit to the openhands Team on Vercel.

A member of the Team first needs to authorize it.

jamiechicago312 and others added 4 commits May 22, 2026 11:40
ChatStatusIndicator had two separately-keyed motion.span children inside
<AnimatePresence mode="wait">. framer-motion's wait mode expects exactly ONE
child to exit before the next enters; two children trigger the repeated warning:
  "attempting to animate multiple children within AnimatePresence,
   but its mode is set to 'wait'"

Fix: wrap both elements in a single motion.span with unified key={status}
and className="contents" (CSS display:contents preserves flex layout).

Co-authored-by: openhands <openhands@all-hands.dev>
Python on Windows defaults to the system ANSI codepage (cp1252). The agent-server
writes metadata JSON containing emoji (e.g. U+2705 ✅) that cp1252 cannot encode,
producing UnicodeEncodeError → POST /api/conversations 500. Old UTF-8 conversation
files also fail to load at startup (UnicodeDecodeError). PYTHONUTF8=1 enables
Python's UTF-8 mode (PEP 540) for the process, matching Linux/macOS behaviour.

Co-authored-by: openhands <openhands@all-hands.dev>
Python on Windows defaults to the system ANSI codepage (cp1252). The agent-server
writes metadata JSON containing emoji (e.g. U+2705 ✅) that cp1252 cannot encode,
producing UnicodeEncodeError → POST /api/conversations 500. Old UTF-8 conversation
files also fail to load at startup (UnicodeDecodeError). PYTHONUTF8=1 enables
Python's UTF-8 mode (PEP 540) for the process, matching Linux/macOS behaviour.

Co-authored-by: openhands <openhands@all-hands.dev>
@jamiechicago312
Copy link
Copy Markdown
Member Author

Logs to proof this fix is successful and a screenshot

20260522-pr734-succesful-logs.txt

image

@jamiechicago312 jamiechicago312 marked this pull request as ready for review May 22, 2026 17:18
Copy link
Copy Markdown
Contributor

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Windows Path Fix: Excellent Solution

The core fix is elegant and well-tested. Moving the win32 check before npm_execpath correctly avoids the cmd.exe space-splitting issue. The regression test specifically covers the failing scenario (paths with spaces). Bonus: the PYTHONUTF8=1 addition prevents UTF-8 encoding errors on Windows.

[RISK ASSESSMENT]
🟢 LOW - Bug fix that makes Windows dev environment work correctly. No breaking changes, good test coverage, and the cmd.exe approach is the standard Windows pattern for npm script execution.


Was this automated review useful? React with 👍 or 👎 to this review to help us measure review quality.
Workflow run: https://github.com/OpenHands/agent-canvas/actions/runs/26301906834

<motion.span
key={`dot-${status}`}
className="flex-shrink-0 animate-[pulse_1.2s_ease-in-out_infinite]"
key={status}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: This framer-motion fix is correct but unrelated to the Windows path issue. Consider either:

  1. Mentioning it in the PR description ("Also fixes a framer-motion AnimatePresence warning in chat status indicator")
  2. Moving it to a separate PR for cleaner change tracking

Not a blocker - the fix itself is sound (wrapping both elements in a single keyed motion.div with className="contents" is the right solution for mode="wait").

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants