Skip to content

fix(evals): resolve windows EINVAL quoting issue in spawnSync#1931

Open
tearf001 wants to merge 1 commit intobrowserbase:mainfrom
tearf001:fix-windows-build-quoting
Open

fix(evals): resolve windows EINVAL quoting issue in spawnSync#1931
tearf001 wants to merge 1 commit intobrowserbase:mainfrom
tearf001:fix-windows-build-quoting

Conversation

@tearf001
Copy link
Copy Markdown

@tearf001 tearf001 commented Mar 31, 2026

Description

This PR resolves an issue where running pnpm install (and consequently the prepare script) fails on Windows environments due to spawnSync errors within the @browserbasehq/stagehand-evals package.

The Problem

  1. EINVAL on .cmd files: On Windows, Node.js refuses to execute .cmd scripts (like pnpm or npm) via spawnSync without the shell: true option, resulting in a silent EINVAL crash.
  2. Space Quoting Corruption: When shell: true is added to fix the EINVAL crash, the Windows cmd.exe parser inadvertently breaks spaced arguments. Specifically, the --banner:js="#!/usr/bin/env node" argument passed to esbuild was being split, causing esbuild to fail with: [ERROR] Must use "outdir" when there are multiple input files.

The Solution

  • Refactored build-cli.ts to use the native esbuild Node API: Instead of spawning a child pnpm exec esbuild process, the script now uses esbuild.buildSync(). This entirely bypasses the Windows shell quoting nightmare, is more robust, and is slightly faster.
  • Restored shell: true dynamically for safe commands: For other .cmd files like tsc and npm link that don't pass complex spaced arguments, shell: process.platform === "win32" was safely added to spawnSync to prevent the EINVAL crashes.

These changes are constrained to Windows using process.platform === "win32", ensuring that macOS and Linux builds remain 100% unaffected.

Testing

  • Verified pnpm run build succeeds on Windows natively.
  • Verified pnpm run build succeeds on WSL / Linux.

Summary by cubic

Fixes Windows install/build failures in @browserbasehq/stagehand-evals caused by spawnSync EINVAL on .cmd and broken argument quoting. Switches the CLI build to the esbuild Node API and adds safe Windows-specific spawning.

  • Bug Fixes
    • Use esbuild.buildSync() instead of pnpm exec esbuild, preserving the #!/usr/bin/env node banner and existing bundling config.
    • Add Windows-only spawning fixes: shell: true for safe commands (pnpm run build, npm link) and platform-aware pnpm resolution (pnpm.cmd on Windows).
    • Changes are Windows-scoped; macOS/Linux paths unchanged.

Written for commit afcd7b4. Summary will update on new commits. Review in cubic

On Windows, Node enforces shell:true for .cmd files. However, cmd.exe corrupts spaced arguments like --banner. This bypasses the issue by utilizing esbuild's Node API, while restoring shell:true for standard spawn commands to prevent EINVALs during the prepare script.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 31, 2026

⚠️ No Changeset found

Latest commit: afcd7b4

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

This PR is from an external contributor and must be approved by a stagehand team member with write access before CI can run.
Approving the latest commit mirrors it into an internal PR owned by the approver.
If new commits are pushed later, the internal PR stays open but is marked stale until someone approves the latest external commit and refreshes it.

@github-actions github-actions Bot added external-contributor Tracks PRs mirrored from external contributor forks. external-contributor:awaiting-approval Waiting for a stagehand team member to approve the latest external commit. labels Mar 31, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 3 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.
Architecture diagram
sequenceDiagram
    participant User as Developer / CLI
    participant Runner as run.ts
    participant BuildScript as build-cli.ts
    participant ESBuild as esbuild (Node API)
    participant OS as OS Shell (CMD/sh)
    participant PkgMgr as pnpm / npm

    User->>Runner: Execute eval runner
    
    rect rgb(240, 240, 240)
    Note over Runner,PkgMgr: Phase 1: Parent Build Process
    alt Platform is Windows
        Runner->>OS: CHANGED: spawnSync("pnpm run build") with { shell: true }
    else Platform is Unix/macOS
        Runner->>OS: spawnSync("pnpm run build")
    end
    OS->>PkgMgr: Execute build scripts
    PkgMgr->>BuildScript: Invoke build-cli.ts
    end

    rect rgb(230, 245, 230)
    Note over BuildScript,ESBuild: Phase 2: CLI Bundling (The "Quoting Bug" Fix)
    BuildScript->>ESBuild: NEW: esbuild.buildSync({ banner: { js: "#!..." }, ... })
    Note right of ESBuild: Direct Node API call bypasses<br/>Windows shell argument splitting
    ESBuild-->>BuildScript: Compilation complete (dist/cli/cli.js)
    end

    rect rgb(240, 240, 240)
    Note over BuildScript,PkgMgr: Phase 3: Post-Build & Linking
    BuildScript->>BuildScript: fs.chmodSync(cli.js, 0o755)
    
    alt Platform is Windows
        BuildScript->>OS: CHANGED: spawnSync("npm link") with { shell: true }
        OS->>PkgMgr: Execute npm.cmd link
    else Platform is Unix/macOS
        BuildScript->>OS: spawnSync("npm link")
        OS->>PkgMgr: Execute npm link
    end
    
    PkgMgr-->>BuildScript: Global link created
    end

    BuildScript-->>Runner: Success
    Runner-->>User: Process Exit (0)
Loading

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

Labels

external-contributor:awaiting-approval Waiting for a stagehand team member to approve the latest external commit. external-contributor Tracks PRs mirrored from external contributor forks.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant