JuliusBrussee/caveman · error
cannot safely launch Windows command shim: ${command}
Error message
cannot safely launch Windows command shim: ${command} What it means
On win32, when caveman must spawn a `.cmd`/`.bat` shim it refuses to use the shell file directly (CVE-2024-27980-style command-injection risk in cmd shims). It first stats the shim; if the path is not a regular file or exceeds 256 KiB it throws this error, because parsing an oversized or non-file shim is neither safe nor useful. This is the size/existence gate before the shim-content parse.
Source
Thrown at packages/cli/src/portable-command.ts:25
for (const line of source.split(/\r?\n/)) {
if (!/(?:\bnode(?:\.exe)?\b|_prog)/i.test(line) || !/%\*/.test(line)) continue;
const match = line.match(/"%(?:dp0%|~dp0)\\([^"\r\n]+\.(?:cjs|mjs|js))"\s+%\*/i);
if (match) return match[1]!;
}
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
- Check the path: run `dir <command>` and confirm it is a regular file well under 256 KiB (npm shims are a few hundred bytes).
- Reinstall the package that owns the shim (npm reinstall / pnpm install) to regenerate a clean, small shim.
- Point caveman at the underlying Node script or a native .exe instead of the .cmd shim.
- If a wrapper script genuinely must be large, invoke node directly on your script and skip the .cmd indirection.
Example fix
# before
portableInvocation("C:\tools\mytool.cmd", args) # mytool.cmd is 1 MiB
# after: small Node shim or direct exe
portableInvocation("C:\tools\mytool.exe", args) Defensive patterns
Strategy: try-catch
Validate before calling
import { statSync } from "node:fs";
function shimSafeToLaunch(command: string): boolean {
if (process.platform !== "win32" || !/\.(?:cmd|bat)$/i.test(command)) return true;
try {
const s = statSync(command);
return s.isFile() && s.size <= 256 * 1024;
} catch {
return false;
}
} Try / catch
try {
const invocation = portableInvocation(cmd, args);
} catch (e) {
if (e instanceof Error && e.message.startsWith("cannot safely launch Windows command shim")) {
return spawnFallback(nativeExeFor(cmd), args); // prefer a native .exe
}
throw e;
} Prevention
- Prefer native .exe distributions of tools on Windows.
- Regenerate npm shims after partial installs instead of reusing suspect .cmd files.
- Validate shim files are regular and small before delegating launch to caveman.
When it happens
Trigger: portableInvocation(command, args) on Windows where command matches /\.(cmd|bat)$/i and statSync shows a directory, a symlink/pipe rather than a plain file, or a shim file larger than 256 KiB.
Common situations: Passing a directory that merely ends in .cmd, a broken npm/pnpm install producing a bloated or malformed shim, PATH resolution landing on a stub .cmd from an unpacked archive, or antivirus replacing the shim with something huge.
Related errors
- cannot safely launch non-Node Windows command shim: ${comman
- Windows command shim target is missing: ${script}
- cannot safely launch Windows command shim: ${executable}
- cannot safely launch non-Node Windows command shim: ${execut
- cannot safely launch non-Node Windows command shim: ${execut
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/5cd3c5f518c90aa9.
Report an issue: GitHub.