JuliusBrussee/caveman · error
cave_sandbox_tool_definition_mismatch
cave_sandbox_tool_definition_mismatch
Error message
cave_sandbox_tool_definition_mismatch
What it means
The worker hashes the selected tool definition with toolDefinitionSHA256 and compares against request.toolDefinitionSha256 supplied by the parent. A mismatch means the tool definition the worker resolved is not the exact one the parent vetted — the same fail-closed drift check as the root digest, scoped to one tool.
Source
Thrown at packages/agent/src/tool-worker.ts:131
const delegated = definition.tools.filter((item) =>
item.name === name && item.runtime?.kind === "subagent"
);
if (delegated.length !== 1) throw new Error("cave_sandbox_unknown_subagent");
const child = delegated[0]!.runtime!.definition as AgentDefinition;
if (!child || child.kind !== "agent") {
throw new Error("cave_sandbox_subagent_definition_invalid");
}
if (visited.has(child)) throw new Error("cave_sandbox_subagent_cycle");
visited.add(child);
definition = child;
}
const selectedTools = definition.tools.filter((item) => item.name === request.tool);
if (selectedTools.length !== 1 || selectedTools[0]!.runtime?.kind === "subagent") {
throw new Error("cave_sandbox_unknown_tool");
}
const selected = selectedTools[0]!;
if (toolDefinitionSHA256(selected) !== request.toolDefinitionSha256) {
throw new Error("cave_sandbox_tool_definition_mismatch");
}
if (selected.effect !== "read" && request.allowSideEffects !== true) {
throw new Error("cave_sandbox_side_effect_denied");
}
const value = await selected.execute(request.params as never, AbortSignal.timeout(selected.timeoutMs));
writeResult({ ok: true, value });
} catch (error) {
writeResult({ ok: false, code: failureCode(error) });
}
View on GitHub (pinned to 27d5a3981a)
Solutions
- Make tool definitions deterministic (stable schemas, timeouts, effect strings; no timestamps/random ids).
- Compute both rootDefinitionSha256 and toolDefinitionSha256 from the same immutable staged snapshot the worker imports.
- Restart dev sessions after editing tool definitions so hashes and imports agree.
Example fix
// before
tool({ name: "fetch", timeoutMs: Date.now() % 60000, ... }) // unstable hash input
// after
tool({ name: "fetch", timeoutMs: 30_000, ... }) // stable hash input Defensive patterns
Strategy: validation
Validate before calling
import { toolDefinitionSHA256 } from "@caveman-ai/agent/build.js";
const selected = def.tools.find((t) => t.name === request.tool)!;
if (toolDefinitionSHA256(selected) !== request.toolDefinitionSha256) throw new Error("tool digest drift; re-derive before spawn"); Prevention
- Keep tool definitions deterministic (fixed timeoutMs, stable schema objects).
- Derive both digests and the import from one immutable snapshot; never across a hot-reload boundary.
When it happens
Trigger: Tool definition (name, schema, effect, timeoutMs, execute identity inputs) changed between the parent's hash computation and the worker's import; nondeterministic fields inside the tool definition; parent hashed a different tool than the one name resolution found.
Common situations: Hot reload or source-graph restage between parent inspection and worker spawn; tools built with closures capturing changing config but hashed on unstable metadata; version skew between parent and sandbox copy.
Related errors
- cave_sandbox_definition_mismatch
- cave_harness_plan_digest_mismatch
- cave_sandbox_agent_export_missing
- cave_sandbox_unknown_subagent
- cave_sandbox_subagent_definition_invalid
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/786815d9f5d2e6c0.
Report an issue: GitHub.