{"record":{"id":"ac1cbd6c593ecf32","repo":"JuliusBrussee/caveman","slug":"cannot-safely-launch-non-node-windows-command-shim-ac1cbd","errorCode":null,"errorMessage":"cannot safely launch non-Node Windows command shim: ${executable}; install a native .exe","messagePattern":"cannot safely launch non-Node Windows command shim: (.+?); install a native \\.exe","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/pi-extension/src/portable-command.ts","lineNumber":88,"sourceCode":"// Fail-open by contract: the hook bridge treats a throw the same as a spawn\n// error, and an unresolvable command falls through to the next candidate, so a\n// shim we cannot parse must never take down the caller.\nexport function portableInvocation(\n  command: string,\n  args: readonly string[],\n  platform: NodeJS.Platform = process.platform,\n  env: NodeJS.ProcessEnv = process.env,\n): PortableInvocation {\n  if (platform !== \"win32\") return { command, args: [...args] };\n  const executable = resolveWindowsCommand(command, env) ?? command;\n  if (!/\\.(?:cmd|bat)$/i.test(executable)) return { command: executable, args: [...args] };\n  const stat = statSync(executable);\n  if (!stat.isFile() || stat.size > 256 * 1024) {\n    throw new Error(`cannot safely launch Windows command shim: ${executable}`);\n  }\n  const shimScript = parseWindowsNodeShim(readFileSync(executable, \"utf8\"));\n  if (!shimScript) {\n    throw new Error(`cannot safely launch non-Node Windows command shim: ${executable}; install a native .exe`);\n  }\n  const script = /^[A-Za-z]:[\\\\/]/.test(shimScript)\n    ? shimScript\n    : resolve(dirname(executable), ...shimScript.split(/[\\\\/]+/));\n  if (!statSync(script).isFile()) {\n    throw new Error(`Windows command shim target is missing: ${script}`);\n  }\n  return { command: process.execPath, args: [script, ...args] };\n}\n","sourceCodeStart":70,"sourceCodeEnd":98,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/pi-extension/src/portable-command.ts#L70-L98","documentation":"When a Windows `.cmd`/`.bat` shim passes the size/type check, `portableInvocation` reads it and attempts to parse it as a Node shim script via `parseWindowsNodeShim`. If the parse yields nothing (packages/pi-extension/src/portable-command.ts:88), the shim is not a recognized Node launcher, and launching it would require invoking cmd.exe — which the library refuses — so it throws and suggests installing a native .exe instead.","triggerScenarios":"A `.cmd`/`.bat` shim whose content does not match the expected Node shim pattern (e.g. a hand-written batch file, a shim for a non-Node CLI, a shim format from a different package manager).","commonSituations":"Custom batch wrappers on PATH; CLIs installed via vendors that emit non-Node .cmd launchers; heavily customized npm global shims.","solutions":["Install a native .exe build of the tool so no shim parsing is needed.","Point the configuration at the underlying JS entry point via node directly instead of the .cmd shim.","Regenerate the shim with the standard npm installer so it matches the expected Node shim format."],"exampleFix":"// before\nportableInvocation('my-custom-wrapper.cmd', args) // hand-written batch\n// after\nportableInvocation(process.execPath, [nodeModules('my-cli/bin/cli.js'), ...args])","handlingStrategy":"fallback","validationCode":"import { readFileSync } from 'node:fs';\nfunction looksLikeNodeShim(p: string) {\n  try { return /node(?:\\.exe)?/i.test(readFileSync(p, 'utf8')); } catch { return false; }\n}","typeGuard":"const isNodeShimFile = (p: string): boolean => {\n  try { const s = readFileSync(p, 'utf8'); return s.includes('node') && s.length <= 256 * 1024; } catch { return false; }\n};","tryCatchPattern":"try {\n  const inv = portableInvocation(command, args, env);\n} catch (e) {\n  if (e instanceof Error && /non-Node Windows command shim/.test(e.message)) {\n    // fall back to invoking the JS entry point with node directly\n    return portableInvocation(process.execPath, [resolveJsEntry(command), ...args]);\n  }\n  throw e;\n}","preventionTips":["Install tools that ship native .exe launchers on Windows.","Avoid hand-written .cmd wrappers for commands this library must launch.","Use standard npm-installed shims, which follow the recognized Node shim format."],"tags":["windows","command-shim","node","launch"],"backgroundTag":"unsupported-platform","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}