{"record":{"id":"3547a6aa2a8a49f9","repo":"JuliusBrussee/caveman","slug":"cannot-safely-launch-non-node-windows-command-shim-3547a6","errorCode":null,"errorMessage":"cannot safely launch non-Node Windows command shim: ${executable}","messagePattern":"cannot safely launch non-Node Windows command shim: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/subagent-tax/lib/process-tree.mjs","lineNumber":53,"sourceCode":"  return null;\n}\n\nexport function portableProcessInvocation(\n  command,\n  args,\n  { platform = process.platform, env = process.env, execPath = process.execPath } = {},\n) {\n  if (platform !== \"win32\") return { command, args: [...args] };\n  const executable = resolveWindowsCommand(command, env);\n  if (!executable) throw Object.assign(new Error(`command not found: ${command}`), { code: \"ENOENT\" });\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 relativeScript = parseWindowsNodeShim(readFileSync(executable, \"utf8\"));\n  if (!relativeScript) {\n    throw new Error(`cannot safely launch non-Node Windows command shim: ${executable}`);\n  }\n  const script = resolve(dirname(executable), ...relativeScript.split(/[\\\\/]+/));\n  if (!statSync(script).isFile()) throw new Error(`Windows command shim target is missing: ${script}`);\n  return { command: execPath, args: [script, ...args] };\n}\n\nexport function harnessSpawnOptions(platform = process.platform) {\n  return {\n    detached: platform !== \"win32\",\n    windowsHide: true,\n  };\n}\n\nexport function forceKillTree(\n  child,\n  {\n    platform = process.platform,\n    kill = process.kill,","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/subagent-tax/lib/process-tree.mjs#L35-L71","documentation":"Thrown by portableProcessInvocation() on win32 when the .cmd/.bat shim was read successfully but parseWindowsNodeShim() cannot extract a relative script path from it. The function only launches shims it can prove are standard Node/npm wrappers (which reference a node script with %~dp0-relative logic); anything else — a plain batch file, a custom launcher, a shell script named .cmd — is rejected rather than executed, because executing arbitrary batch content indirectly is unsafe.","triggerScenarios":"Calling portableProcessInvocation with platform win32 where the resolved command is a hand-written .cmd/.bat (e.g. \"@echo off\\nmyapp.exe %*\") or a shim in a format the parser does not recognize (yarn/pnpm/pnpm-style or volta shims whose internals differ from npm's node.exe invocation pattern).","commonSituations":"A user installed the CLI through a non-npm package manager whose shim format differs; a project checked in a custom .cmd wrapper; the shim format changed with a newer npm/pnpm/bun release.","solutions":["Bypass the shim: pass the absolute path to the underlying executable or Node script as command (Node scripts can be launched as [execPath, script, ...args] yourself).","If the tool is npm-distributed, reinstall it with npm so a standard npm .cmd shim is generated.","If you maintain the shim, rewrite it as a standard npm-style Node wrapper so parseWindowsNodeShim can extract the script target."],"exampleFix":"// before\nconst inv = portableProcessInvocation(\"pnpm\", [\"run\", \"build\"], { platform: \"win32\" }); // non-npm shim -> throws\n\n// after\nconst inv = { command: process.execPath,\n  args: [\"C:/proj/node_modules/pnpm/bin/pnpm.cjs\", \"run\", \"build\"] };","handlingStrategy":"fallback","validationCode":"import { readFileSync } from \"node:fs\";\nfunction looksLikeNodeShim(executable) {\n  const text = readFileSync(executable, \"utf8\");\n  return /node(\\.exe)?\"? \"%~dp0/i.test(text) || /node_modules/.test(text);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const inv = portableProcessInvocation(cmd, args, { platform: \"win32\" });\n} catch (err) {\n  if (/non-Node Windows command shim/.test(err.message)) {\n    // fallback: launch underlying exe or [execPath, script] directly\n  } else throw err;\n}","preventionTips":["Install CLIs via npm so standard shims are generated.","When wrapping tools yourself, write npm-style Node shims or expose the raw binary."],"tags":["windows","spawn","cmd-shim","security"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}