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
- Verify the binary exists and is executable: `which <bin>` or `ls -l $(which <bin>)`; install it if missing (e.g. `npm i -g <package>`).
- Fix PATH so it includes the binary's directory in the shell where the CLI runs (check ~/.zshrc, ~/.bashrc, CI env).
- Check file permissions: `chmod +x <path-to-bin>`.
- Reinstall the binary for the correct platform/architecture (e.g. wrong-arch Node binary on Apple Silicon vs Intel).
- 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
- Install all agent binaries before invoking the CLI and verify with `which <bin>`.
- Keep install dirs on PATH in non-interactive shells and CI.
- After copying binaries, `chmod +x` them.
- Pin platform-correct builds (avoid copying binaries across architectures).
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
- caveman agent: Cave Runtime failed to start (${error instanc
- cave_stale_lock:${checked.stale.join(",")}: run npm run buil
- cave_transform_registry_unavailable: run caveman setup or se
- caveman-code: neither rg nor grep is available
- caveman-code: host command shell is not available
AI-assisted analysis of JuliusBrussee/caveman@5184b3d11a (2026-08-31).
Data as JSON: /api/errors/7cb0c12aaf6e91ea.
Report an issue: GitHub.