oven-sh/bun · error · BuildError

Failed to spawn pwsh

Error message

Failed to spawn pwsh

What it means

On Windows, scripts/build.ts relaunches itself through vs-shell.ps1 under PowerShell 7 (pwsh) to inherit the Visual Studio environment (PATH with mt.exe/rc.exe/cl.exe, INCLUDE, LIB, WindowsSdkDir) unless VSINSTALLDIR is already set. This BuildError means spawnSync("pwsh", ...) returned an error — pwsh was not found or could not start.

Source

Thrown at scripts/build.ts:70

// ───────────────────────────────────────────────────────────────────────────
// Main
// ───────────────────────────────────────────────────────────────────────────

async function main(): Promise<void> {
  // Windows: re-exec inside the VS dev shell if not already there.
  // The shell provides PATH (mt.exe, rc.exe, cl.exe), INCLUDE, LIB,
  // WindowsSdkDir — things clang-cl can mostly self-detect but nested
  // cmake projects can't. Cheap: VSINSTALLDIR check short-circuits on
  // subsequent runs in the same terminal.
  if (process.platform === "win32" && !process.env.VSINSTALLDIR) {
    const vsShell = join(import.meta.dirname, "vs-shell.ps1");
    const result = spawnSync(
      "pwsh",
      ["-NoProfile", "-NoLogo", "-File", vsShell, process.argv0, import.meta.filename, ...process.argv.slice(2)],
      { stdio: "inherit" },
    );
    if (result.error) {
      throw new BuildError(`Failed to spawn pwsh`, {
        cause: result.error,
        hint: "Is PowerShell 7+ (pwsh) installed?",
      });
    }
    process.exit(result.status ?? 1);
  }

  const args = parseArgs(process.argv.slice(2));

  // Skip on --configure-only / --config-file (ninja regen): those paths
  // return before spawning ninja, so the NO_PROXY mutation can't reach any
  // child and would be pure wasted wall-clock (up to 2s behind a
  // silent-drop firewall).
  if (!args.configureOnly) {
    await maybeBypassProxyForCratesIo();
  }

  // Resolve ConfigureInput: either from --config-file (ninja's generator rule

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Install PowerShell 7: winget install Microsoft.PowerShell, then reopen the terminal
  2. Verify with pwsh -v in the same terminal you build from
  3. If the VS environment is already configured (e.g. a Developer PowerShell), set VSINSTALLDIR to skip the relaunch
  4. Repair or reinstall pwsh if it is on PATH but still fails to spawn

Example fix

# before (pwsh missing)
$ bun bd
BuildError: Failed to spawn pwsh (cause: spawnSync pwsh ENOENT)

# after
$ winget install Microsoft.PowerShell
$ pwsh -v
PowerShell 7.4.6
$ bun bd
Defensive patterns

Strategy: validation

Validate before calling

import { spawnSync } from "node:child_process";
if (process.platform === "win32" && !process.env.VSINSTALLDIR) {
  const probe = spawnSync("pwsh", ["-NoProfile", "$PSVersionTable.PSVersion.ToString()"], { encoding: "utf8" });
  if (probe.error) {
    console.error("pwsh not available — install PowerShell 7 (winget install Microsoft.PowerShell) or set VSINSTALLDIR");
    process.exit(1);
  }
}

Prevention

When it happens

Trigger: Running bun bd / scripts/build.ts on win32 where PowerShell 7 is not installed or not on PATH (only Windows PowerShell 5.1, whose binary is powershell.exe not pwsh.exe), or pwsh exists but cannot execute (permissions, broken install).

Common situations: Fresh Windows machine with VS Build Tools but no PowerShell 7; pwsh installed to a non-PATH location (missing scoop shim, per-user winget install); CI images lacking pwsh.

Related errors


AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16). Data as JSON: /api/errors/517857c1713b5569. Report an issue: GitHub.