JuliusBrussee/caveman · error

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

Error message

cannot safely launch non-Node Windows command shim: ${command}; install a native .exe

What it means

When caveman launches a Windows .cmd/.bat shim it parses the shim text to find the Node script it delegates to, then runs that script with process.execPath — it never executes the batch file through cmd.exe. If parseWindowsNodeShim cannot find a recognizable Node script reference inside the shim, it throws this error with the remediation of installing a native .exe. Supported shims are the standard npm/yarn/pnpm-style Node launchers.

Source

Thrown at packages/cli/src/portable-command.ts:29

  }
  return null;
}

export function portableInvocation(
  command: string,
  args: readonly string[],
  platform: NodeJS.Platform = process.platform,
): PortableInvocation {
  if (platform !== "win32" || !/\.(?:cmd|bat)$/i.test(command)) {
    return { command, args: [...args] };
  }
  const stat = statSync(command);
  if (!stat.isFile() || stat.size > 256 * 1024) {
    throw new Error(`cannot safely launch Windows command shim: ${command}`);
  }
  const relativeScript = parseWindowsNodeShim(readFileSync(command, "utf8"));
  if (!relativeScript) {
    throw new Error(`cannot safely launch non-Node Windows command shim: ${command}; install a native .exe`);
  }
  const script = resolve(dirname(command), ...relativeScript.split(/[\\/]+/));
  if (!statSync(script).isFile()) {
    throw new Error(`Windows command shim target is missing: ${script}`);
  }
  return { command: process.execPath, args: [script, ...args] };
}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Install a native .exe build of the tool and let caveman resolve that instead of the .cmd.
  2. If the target is Node after all, rewrite the .cmd as a standard npm-style shim (a short batch file that runs node with the adjacent .js entry) so the parser can find the script.
  3. Pass the underlying .js entry (or node script path) directly so no shim parsing is involved.

Example fix

:: before: arbitrary batch logic
@echo off
some-tool --raw %*
:: after: standard node shim caveman can parse
@echo off
node "%~dp0\some-tool.js" %*
Defensive patterns

Strategy: type-guard

Validate before calling

import { readFileSync } from "node:fs";

// Mirror of the npm-style shim shapes the parser accepts
const SHIM_RE = /(?:node|"?[^"]*node\.exe"?)\s+"?%~dp0[\\/]?([^"\r\n%]+\.js)/i;
function isNodeShim(command: string): boolean {
  try { return SHIM_RE.test(readFileSync(command, "utf8")); } catch { return false; }
}

Try / catch

try {
  const invocation = portableInvocation(cmd, args);
} catch (e) {
  if (e instanceof Error && e.message.includes("install a native .exe")) {
    throw new ConfigError(`Replace custom batch wrapper ${cmd} with a native .exe or a standard node shim`);
  }
  throw e;
}

Prevention

When it happens

Trigger: portableInvocation on win32 with a .cmd/.bat that passes the size check but whose contents are not a recognizable Node shim — e.g. a batch file doing arbitrary logic, SET/IF blocks, or calling a non-Node binary.

Common situations: Custom .bat wrappers around tools, shims generated by Python/pip (pip.exe launchers) or other non-Node ecosystems, hand-written batch launchers on PATH that caveman discovers, or an edited npm shim whose node invocation line was altered.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/ec776898497fff70. Report an issue: GitHub.