JuliusBrussee/caveman · error · Error

failed to exec ${bin}: ${result.error.message}

Error message

failed to exec ${bin}: ${result.error.message}

What it means

This error is thrown by the CLI when spawning a child process (an agent binary) fails at the OS level — i.e. spawnSync populated result.error. The library throws it to surface the underlying Node spawn failure (e.g. ENOENT, EACCES) with the binary name for context.

Source

Thrown at packages/cli/src/index.ts:5028

async function agentShortcut(rest: string[]) {
  // normalizeAgentShortcutWrapArgs hoists --off/--pixel/--workflow to the
  // front, so a leading flag means explicit session-only wrap intent.
  if (rest[0]?.startsWith("--")) return wrap(rest);
  const agent = findAgent(rest[0] ?? "");
  const native = agent ? nativeAgentId(agent.id) : undefined;
  if (!agent || !native) return wrap(rest);
  // Host help is observational. Never turn `caveman claude --help` into a
  // machine-wide integration install before printing another program's usage.
  if (rest.slice(1).some((arg) => arg === "--help" || arg === "-h")) {
    const bin = which(binOf(agent));
    if (!bin) {
      wrapNotFoundUI(rest[0]!, agent);
      process.exitCode = 127;
      return;
    }
    const invocation = portableInvocation(bin, [...agent.args, ...rest.slice(1)]);
    const result = spawnSync(invocation.command, invocation.args, { stdio: "inherit" });
    if (result.error) throw new Error(`failed to exec ${bin}: ${result.error.message}`);
    process.exitCode = result.status ?? 1;
    return;
  }
  // A Cave Build lock is enforced at the wrap door (claudeCaveBuildEnv); the
  // native door applies none of its transforms, so a locked project must keep
  // routing through wrap or the lock would be silently unenforced.
  if (existsSync(join(process.cwd(), ".caveman", "agent.lock.json"))) return wrap(rest);
  // First-run disclosure comes before the first persistent write, mirroring wrap.
  await firstRunExperience();
  try {
    // An existing journal means the machine-wide install already owns routing —
    // exactly what plain `<agent>` uses — so launch directly without re-probing
    // (status probes spawn three subprocesses); `caveman doctor <agent>` stays
    // the repair door for drifted installs.
    if (!readNativeJournal(native)) enableNative([native]);
  } catch (error) {
    process.stderr.write(`${mark("warn")} native enable failed: ${(error as Error).message} — using session-only wrap for this run\n`);
    return wrap(rest);

View on GitHub (pinned to 5184b3d11a)

Solutions

  1. Verify the binary exists and is executable: `which <bin>` or `ls -l $(which <bin>)`; install it if missing (e.g. `npm i -g <package>`).
  2. Fix PATH so it includes the binary's directory in the shell where the CLI runs (check ~/.zshrc, ~/.bashrc, CI env).
  3. Check file permissions: `chmod +x <path-to-bin>`.
  4. Reinstall the binary for the correct platform/architecture (e.g. wrong-arch Node binary on Apple Silicon vs Intel).
  5. Run the binary directly to see the raw OS error and confirm it starts outside the CLI.

Example fix

// before (binary missing from PATH)
export PATH=/usr/local/bin:/usr/bin:/bin
// after
export PATH="$HOME/.local/bin:$PATH"  # ensure agent install dir is on PATH
Defensive patterns

Strategy: try-catch

Validate before calling

const which = spawnSync("which", [bin]); if (which.status !== 0) throw new Error(`${bin} not found on PATH`);

Type guard

function isSpawnError(r: ReturnType<typeof spawnSync>): r is typeof r & { error: Error } { return r.error instanceof Error; }

Try / catch

try {
  // run the CLI subcommand that spawns the agent binary
} catch (e) {
  if (e instanceof Error && e.message.startsWith("failed to exec ")) {
    console.error(`${e.message} — is the binary installed and on PATH?`);
    process.exitCode = 127;
  } else throw e;
}

Prevention

When it happens

Trigger: Running a subcommand that resolves to a binary (via portableInvocation) where the executable does not exist at the resolved path, lacks execute permission, or otherwise cannot be spawned by spawnSync.

Common situations: Agent CLI not installed or not on PATH; PATH differs inside wrappers/non-interactive shells; binary installed for a different platform/architecture; permissions lost after copying a binary; antivirus or sandbox blocking exec.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@5184b3d11a (2026-08-31). Data as JSON: /api/errors/7cb0c12aaf6e91ea. Report an issue: GitHub.