JuliusBrussee/caveman · error
cave_sandbox_tool_failed
cave_sandbox_tool_failed
Error message
cave_sandbox_tool_failed
What it means
The sandboxed tool worker answered with a result frame { ok: false } carrying no structured code, so the executor throws the generic fallback (result.code ?? 'cave_sandbox_tool_failed'). Something inside the worker failed - the tool threw a plain unstructured error, the worker process died, or the call was aborted by the timeout/parent signal - and no specific code survived the fd 3 length-prefixed result frame.
Source
Thrown at packages/agent/src/runtime.ts:4866
reject(new Error(`cave_sandbox_failed:${redactSandboxError(Buffer.concat(stderr).toString("utf8"))}`));
return;
}
reject(new Error("cave_sandbox_invalid_output"));
});
combined.addEventListener("abort", onAbort, { once: true });
if (combined.aborted) onAbort();
child.stdin.end(JSON.stringify({
entry: pathToFileURL(entryPath).href,
agentPath: executionContext.agentPath,
rootDefinitionSha256: executionContext.rootDefinitionSha256,
toolDefinitionSha256,
tool: toolName,
params,
allowSideEffects,
allowNetwork: profile?.network === true,
}));
});
if (!result.ok) throw new Error(result.code ?? "cave_sandbox_tool_failed");
return result.value;
} finally {
await rm(workspace, { recursive: true, force: true });
}
}
/**
* Above this many per-file `--allow-fs-read` flags, collapse the staged source
* files to their common ancestor directory. A large project would
* otherwise blow the OS argument limit (E2BIG) and the tool could not spawn at
* all. The collapse is safe here: `sourceFiles` are paths inside the per-run
* STAGED COPY, which already contains only the reachable source graph — never
* the real project root with its .env and credentials.
*/
const SANDBOX_FS_READ_FLAG_THRESHOLD = 1024;
function commonAncestorDir(paths: readonly string[]): string {
const dirs = paths.map((path) => resolve(dirname(path)));View on GitHub (pinned to 766dce6b13)
Solutions
- Reproduce the tool outside the sandbox with the same params to see the underlying error
- Raise timeoutMs if the abort path is the cause
- Make the tool throw errors that carry a machine-readable code so result.code is present and specific
- Validate params before dispatch and check the tool's staged entry/dependency graph imports cleanly
Example fix
// before: tool throws a plain error -> generic code
run: async (params) => { throw new Error('boom'); }
// after: throw with a code the worker frame preserves
run: async (params) => { const e = new Error('boom'); (e as any).code = 'my_tool_parse_failed'; throw e; } Defensive patterns
Strategy: try-catch
Try / catch
try {
return await runSandboxedTool(params);
} catch (error) {
if (error instanceof Error && error.message === 'cave_sandbox_tool_failed') {
// generic worker failure: reproduce outside the sandbox to get the real error
const real = await reproduceUnsandboxed(params);
throw new Error(`sandboxed tool failed; unsandboxed repro says: ${real?.message ?? 'unknown'}`);
}
throw error;
} Prevention
- Throw errors that carry a machine-readable code from tool code so result.code is specific, not the fallback
- Set timeoutMs comfortably above the tool's worst-case runtime
- Verify the tool entry and its staged dependency graph import cleanly inside the sandbox
- Validate params before dispatch; many unstructured tool errors are input validation failures
When it happens
Trigger: Tool code throwing a plain Error (no cave_ code) inside the sandbox worker; worker killed by AbortSignal.timeout(timeoutMs) or the parent signal (combined.aborted); worker crash (OOM, import failure of the entry module); malformed/truncated result frame from the worker.
Common situations: Long-running tools hitting a tight timeoutMs; tool entry modules that fail to import inside the sandbox (missing staged dependency); errors from third-party libraries bubbling unstructured; OOM on large inputs.
Related errors
- caveman build: config must use strict lock and required sand
- cave_live_eval_sandbox_profile_missing
- cave_live_eval_sandbox_profile_escapes_root
- cave_live_eval_sandbox_profile_invalid
- cave_host_sandbox_nested_under_required
AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18).
Data as JSON: /api/errors/8c582e4f9cdffcf7.
Report an issue: GitHub.