JuliusBrussee/caveman · error · Error

cannot safely launch non-Node Windows command shim

Error message

cannot safely launch non-Node Windows command shim: ${executable}

What it means

When a Windows .cmd/.bat shim passes the size/file checks, the library parses it with parseWindowsNodeShim() to extract the relative Node script it delegates to. If the shim's contents do not match the expected Node-shim pattern (no relative script found), the library refuses to launch it, since it would otherwise have to execute an opaque batch file. The message includes the shim path.

Solutions

  1. Run the tool directly instead of via its shim: invoke node with the real entry script, or the tool's native executable.
  2. Check what the shim contains (open the reported path) — if it is not a Node shim, it is out of scope for this launcher.
  3. Regenerate standard npm shims (npm install / npm rebuild) if a package manager rewrote them.
  4. Wrap the call in a small .js entry point or use a cross-platform JS CLI equivalent of the batch tool.

Example fix

// before
spawn("deploy.cmd", ["--prod"]); // non-Node batch shim, throws
// after
spawn("powershell.exe", ["-File", "deploy.ps1", "--prod"]);
Defensive patterns

Strategy: fallback

Validate before calling

import { readFileSync } from "node:fs";
function isNodeShim(executable) {
  if (!/\.(?:cmd|bat)$/i.test(executable)) return true;
  try { return Boolean(readFileSync(executable, "utf8").match(/node/i) && /%~dp0|"%~dp0"/.test(readFileSync(executable, "utf8"))); }
  catch { return false; }
}

Try / catch

try {
  child = portableProcessInvocation(command, args, env, process.platform);
} catch (e) {
  if (e.message.includes("non-Node Windows command shim")) {
    // run the tool natively instead of through its batch wrapper
    child = spawnNativeAlternative(command, args);
  } else throw e;
}

Prevention

When it happens

Trigger: portableProcessInvocation() on win32 resolving a .cmd/.bat executable whose readFileSync content is not a standard node "...%~dp0...\script.js" style shim — e.g. a hand-written batch wrapper, a shim for a non-Node tool (robocopy.cmd, a custom deploy.bat), or a shim rewritten by another tool manager.

Common situations: Trying to spawn a non-Node .cmd utility through this library; pnpm/yarn re-generated shims in a different format; a corporate wrapper .bat around a tool; antivirus or a provisioning script replacing stock npm shims.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/3547a6aa2a8a49f9. Report an issue: GitHub.

Appendix: source

Thrown at packages/subagent-tax/lib/process-tree.mjs:57

  return null;
}

export function portableProcessInvocation(
  command,
  args,
  { platform = process.platform, env = process.env, execPath = process.execPath } = {},
) {
  if (platform !== "win32") return { command, args: [...args] };
  const executable = resolveWindowsCommand(command, env);
  if (!executable) throw Object.assign(new Error(`command not found: ${command}`), { code: "ENOENT" });
  if (!/\.(?:cmd|bat)$/i.test(executable)) return { command: executable, args: [...args] };
  const stat = statSync(executable);
  if (!stat.isFile() || stat.size > 256 * 1024) {
    throw new Error(`cannot safely launch Windows command shim: ${executable}`);
  }
  const relativeScript = parseWindowsNodeShim(readFileSync(executable, "utf8"));
  if (!relativeScript) {
    throw new Error(`cannot safely launch non-Node Windows command shim: ${executable}`);
  }
  const script = /^[A-Za-z]:[\\/]/.test(relativeScript)
    ? relativeScript
    : resolve(dirname(executable), ...relativeScript.split(/[\\/]+/));
  if (!statSync(script).isFile()) throw new Error(`Windows command shim target is missing: ${script}`);
  return { command: execPath, args: [script, ...args] };
}

export function harnessSpawnOptions(platform = process.platform) {
  return {
    detached: platform !== "win32",
    windowsHide: true,
  };
}

export function forceKillTree(
  child,
  {

View on GitHub (pinned to 3ee70a1026)