JuliusBrussee/caveman · error · Error

Windows command shim target is missing

Error message

Windows command shim target is missing: ${script}

What it means

After parsing a Windows Node shim, the library resolves the shim's relative target script to an absolute path and verifies it exists with statSync(script).isFile(). If the target file is missing (stale shim pointing at a removed/moved script, or a bad install), it throws this error naming the resolved script path rather than letting spawn fail obscurely.

Solutions

  1. Reinstall dependencies to regenerate shims and their targets: rm -rf node_modules package-lock (as appropriate) then npm install / npm ci.
  2. Verify the reported script path exists; if not, the owning package is broken — reinstall that single package (npm install <pkg> --force).
  3. Check that the package version's bin entry matches the shim; clear stale shims after an upgrade.
  4. As a workaround, invoke the target script via node directly once you know its real location.

Example fix

// before: stale shim -> target removed
spawn("mytool", []); // shim target missing
// after
// regenerate: npm ci
spawn("mytool", []); // shim and target consistent
Defensive patterns

Strategy: validation

Validate before calling

import { statSync, existsSync } from "node:fs";
import { dirname, resolve } from "node:path";
function shimTargetExists(executable, relativeScript) {
  const script = /^[A-Za-z]:[\\/]/.test(relativeScript)
    ? relativeScript
    : resolve(dirname(executable), ...relativeScript.split(/[\\/]+/));
  return existsSync(script) && statSync(script).isFile();
}

Try / catch

try {
  child = portableProcessInvocation(command, args, env, process.platform);
} catch (e) {
  if (e.message.startsWith("Windows command shim target is missing")) {
    console.error("Stale node_modules shim — run npm ci and retry");
    throw e;
  } else throw e;
}

Prevention

When it happens

Trigger: portableProcessInvocation() on win32 where the .cmd shim parses to a relative script path that, resolved against dirname(executable), does not exist or is not a file — e.g. node_modules/<pkg>/bin/x.cmd pointing to a lib file deleted by a partial install or pruned dependency.

Common situations: node_modules partially deleted or out of sync with package.json; a package upgraded and its bin target renamed while an old shim remained; pnpm store pruning; switching branches without reinstalling dependencies.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/d8acf46d13a57bca. Report an issue: GitHub.

Appendix: source

Thrown at packages/subagent-tax/lib/process-tree.mjs:62

  args,
  { platform = process.platform, env = process.env, execPath = process.execPath } = {},
) {
  if (platform !== "win32") return { command, args: [...args] };
  const executable = resolveWindowsCommand(command, env);
  if (!executable) throw Object.assign(new Error(`command not found: ${command}`), { code: "ENOENT" });
  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 relativeScript = parseWindowsNodeShim(readFileSync(executable, "utf8"));
  if (!relativeScript) {
    throw new Error(`cannot safely launch non-Node Windows command shim: ${executable}`);
  }
  const script = /^[A-Za-z]:[\\/]/.test(relativeScript)
    ? relativeScript
    : resolve(dirname(executable), ...relativeScript.split(/[\\/]+/));
  if (!statSync(script).isFile()) throw new Error(`Windows command shim target is missing: ${script}`);
  return { command: execPath, args: [script, ...args] };
}

export function harnessSpawnOptions(platform = process.platform) {
  return {
    detached: platform !== "win32",
    windowsHide: true,
  };
}

export function forceKillTree(
  child,
  {
    platform = process.platform,
    kill = process.kill,
    taskkill = spawnSync,
  } = {},
) {

View on GitHub (pinned to 3ee70a1026)