JuliusBrussee/caveman · error · Error
cannot safely launch Windows command shim
Error message
cannot safely launch Windows command shim: ${executable} What it means
Thrown by portableInvocation() on Windows when a resolved command resolves to a .cmd/.bat shim that is unsafe to execute directly: it is not a regular file or exceeds 256 KiB. Launching .cmd/.bat files via spawn is both a command-injection risk and unreliable for huge auto-generated npm shims, so the library refuses and requires a safe native executable. There is a sibling error for shims whose script is not a Node shim.
Solutions
- Install a native .exe version of the tool (e.g. via npm global with node, or the vendor's Windows installer) instead of relying on the .cmd shim.
- Delete and reinstall the package to regenerate a clean, small .cmd shim (`npm install -g <pkg>`).
- Ensure the resolved path is a regular file; remove directories/files shadowing the command on PATH.
- Call the underlying node script directly: `node <pkg-root>/bin/cli.js ...` instead of the shim.
Example fix
// before (Windows)
spawn("npm.cmd", ["run", "build"]) // may throw: shim unsafe (size/file)
// after
spawn("node", [require.resolve("npm/bin/npm-cli.js"), "run", "build"], { windowsHide: true }) Defensive patterns
Strategy: validation
Validate before calling
import { statSync } from "fs";
function isSafeCmdShim(p: string): boolean {
if (!/\.(?:cmd|bat)$/i.test(p)) return true;
try { const s = statSync(p); return s.isFile() && s.size <= 256 * 1024; }
catch { return false; }
}
// call isSafeCmdShim(resolvedExecutable) before spawning Try / catch
try {
spawn(invocation(cmd, args).command, invocation(cmd, args).args);
} catch (e) {
if (e instanceof Error && e.message.startsWith("cannot safely launch Windows command shim")) {
console.error("Shim unsafe; reinstall the package or use its native .exe/node entry", e.message);
} else throw e;
} Prevention
- Prefer native .exe installs on Windows over .cmd wrappers
- Reinstall npm packages whose shims look oversized or corrupted
- Keep PATH clean of shadowing files with .cmd/.bat extensions
- On Windows, spawn node entry scripts directly instead of .cmd shims
When it happens
Trigger: platform === 'win32' and resolveWindowsCommand() resolved the command to a *.cmd/*.bat file whose statSync shows !isFile() or size > 256*1024 bytes.
Common situations: npm's npx-shim .cmd files left oversized after a broken install, a directory or corrupted file shadowing the command name on PATH, or antivirus quarantine leaving a stub .cmd.
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 non-Node Windows command shim
- unsafe Windows command shim
- cannot safely launch Windows command shim
- cannot safely launch Windows command shim
- ENOENT
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/11a78947a6c27b44.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cli/src/portable-command.ts:65
const candidate = join(directory, name);
if (existsSync(candidate)) return candidate;
}
}
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)