headroomlabs-ai/headroom · error · Error

${command} failed: ${result.error.message}

Error message

${command} failed: ${result.error.message}

What it means

In build_npm_release_assets.mjs, run() wraps spawnSync; result.error is set when the command could not be launched at all (ENOENT, EACCES, EMFILE…) — not when it runs and exits non-zero. The message embeds the underlying spawn error, e.g. 'spawn npm ENOENT'. This is a build-script precondition failure: the required tool is missing or not executable in the build environment.

Source

Thrown at scripts/build_npm_release_assets.mjs:81

function quoteCmdArg(value) {
  const arg = String(value);
  if (/^[A-Za-z0-9_./:=\\-]+$/.test(arg)) {
    return arg;
  }
  return `"${arg.replace(/"/g, '""')}"`;
}

function run(command, args, cwd) {
  console.log(`\n> ${command} ${args.map(quoteCmdArg).join(" ")}`);
  const result = spawnSync(command, args, {
    cwd,
    encoding: "utf8",
    stdio: "inherit",
  });

  if (result.error) {
    throw new Error(`${command} failed: ${result.error.message}`);
  }

  if (result.status !== 0) {
    throw new Error(`${command} failed with exit code ${result.status ?? "unknown"}`);
  }
}

function runNpm(args, cwd) {
  if (process.platform === "win32") {
    run("cmd.exe", ["/d", "/s", "/c", "npm.cmd", ...args], cwd);
    return;
  }
  run("npm", args, cwd);
}

function runNode(args, cwd) {
  run(process.execPath, args, cwd);
}

View on GitHub (pinned to 322425c43b)

Solutions

  1. Check the error string — ENOENT means the binary was not found: install it or fix PATH (e.g. source nvm, add npm's global bin dir)
  2. Verify with 'which <command>' in the exact environment the script runs in (same user, same container)
  3. On CI, run a setup step (actions/setup-node or apt-get install nodejs npm) before the script
  4. If it is EACCES/permission-related, fix the binary's execute bits or run with appropriate permissions

Example fix

# before: CI step runs script without node on PATH
node scripts/build_npm_release_assets.mjs  # 'node failed: spawn npm ENOENT'

# after: ensure toolchain present first
- uses: actions/setup-node@v4
  with: { node-version: 20 }
- run: node scripts/build_npm_release_assets.mjs
Defensive patterns

Strategy: try-catch

Validate before calling

import { spawnSync } from "node:child_process";

function commandLaunchable(cmd: string): boolean {
  const r = spawnSync(cmd, ["--version"], { stdio: "ignore" });
  return r.error === undefined;
}

for (const cmd of ["npm", "node"]) {
  if (!commandLaunchable(cmd)) {
    throw new Error(`${cmd} not launchable — fix PATH before running the release build`);
  }
}

Type guard

function isSpawnLaunchError(e: unknown): e is Error {
  // Distinguish 'could not launch' (ENOENT/EACCES) from 'ran and failed'
  return e instanceof Error && / failed: (spawn|ENOENT|EACCES)/.test(e.message);
}

Try / catch

try {
  buildAssets();
} catch (e) {
  if (e instanceof Error && e.message.includes("failed: spawn")) {
    console.error("Build tool missing from PATH — install it or fix PATH and rerun.");
    process.exitCode = 1;
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: The release asset script invokes npm/node/other commands that do not exist on PATH in the build container or shell; a Windows run hitting a non-.cmd binary; execute permission missing on a helper script.

Common situations: CI image built without Node/npm or with them installed outside PATH; running the script via a different user than the one that installed the toolchain; nvm/fnm environment not loaded in the CI step; local run after switching package managers.

Related errors


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/6abbd99f060f038b. Report an issue: GitHub.