JuliusBrussee/caveman · error · Error
cannot safely launch non-Node Windows command shim
Error message
cannot safely launch non-Node Windows command shim: ${executable}; install a native .exe What it means
Thrown by portableInvocation() on Windows when a .cmd/.bat shim passes the size/file checks but its contents are not a recognizable Node shim (parseWindowsNodeShim returns null). The library will not execute arbitrary batch shims; it demands either a native .exe or a shim whose embedded script points at a Node entry it can launch with process.execPath. This avoids executing untrusted batch logic with user-supplied args.
Solutions
- Install a native .exe build of the command (vendor installer, winget, scoop) and ensure it wins on PATH.
- Replace the custom .cmd wrapper with the standard npm-generated Node shim by reinstalling the package.
- Invoke the target directly: `node path\to\cli.js` for Node tools, bypassing the shim.
- Remove the unknown .cmd from PATH if it is not the tool you intend to run.
Example fix
// before
invocation("mytool") // mytool resolves to custom mytool.cmd batch script -> throws
// after
// install native binary:
winget install mytool
invocation("mytool") // resolves to mytool.exe -> spawns directly Defensive patterns
Strategy: validation
Validate before calling
import { readFileSync, statSync } from "fs";
function looksLikeNodeShim(p: string): boolean {
if (!/\.(?:cmd|bat)$/i.test(p)) return true;
try {
const content = readFileSync(p, "utf8");
return /node/i.test(content) && /%~dp0|node_modules/.test(content); // standard npm shim markers
} catch { return false; }
} Try / catch
try {
const inv = invocation(cmd, args);
spawn(inv.command, inv.args);
} catch (e) {
if (e instanceof Error && e.message.includes("non-Node Windows command shim")) {
console.error("Custom .cmd wrapper rejected; install the native .exe or run node <cli.js> directly");
} else throw e;
} Prevention
- Install native .exe builds of tools on Windows
- Avoid hand-edited .cmd wrappers for CLI tools
- Reinstall packages to restore standard npm-generated shims
- Run Node CLIs via `node path/to/cli.js` to bypass shim parsing entirely
When it happens
Trigger: platform === 'win32', the resolved command ends in .cmd/.bat, and reading the file yields content that parseWindowsNodeShim cannot interpret as a Node launcher shim (e.g. a plain batch script, not the standard npm/node shim format).
Common situations: Third-party tools shipping hand-written .cmd wrappers, corporate wrapper scripts around real binaries, globally-installed tools whose shims were customized or corrupted, or a text file coincidentally named .cmd on PATH.
Understand the failure class
Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.
Related errors
- cannot safely launch Windows command shim
- non-Node Windows command shim
- unsafe Windows command shim
- cannot safely launch non-Node Windows command shim
- cannot safely launch non-Node Windows command shim
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/fd55fd9df74365a6.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/portable-command.ts:69
return undefined;
}
export function portableInvocation(
command: string,
args: readonly string[],
platform: NodeJS.Platform = process.platform,
env: NodeJS.ProcessEnv = process.env,
): PortableInvocation {
if (platform !== "win32") return { command, args: [...args] };
const executable = resolveWindowsCommand(command, env) ?? command;
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 shimScript = parseWindowsNodeShim(readFileSync(executable, "utf8"));
if (!shimScript) {
throw new Error(`cannot safely launch non-Node Windows command shim: ${executable}; install a native .exe`);
}
const script = /^[A-Za-z]:[\\/]/.test(shimScript)
? shimScript
: resolve(dirname(executable), ...shimScript.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 3ee70a1026)