JuliusBrussee/caveman · error
cave_sandbox_tool_definition_mismatch
cave_sandbox_tool_definition_mismatch
Error message
cave_sandbox_tool_definition_mismatch
What it means
The sandbox tool worker resolves the requested tool from the agent definition, computes a SHA-256 fingerprint of the tool's full definition, and compares it to the SHA the caller (the host/parent process) supplied in request.toolDefinitionSha256. A mismatch means the caller's snapshot of the tool definition is stale or was produced from a different definition than the one loaded in this worker, so the worker refuses to execute it to prevent running an unvetted version of the tool.
Solutions
- Regenerate the request (re-derive request.toolDefinitionSha256) from the same definition object/version currently loaded in the worker
- Ensure the parent and worker load the identical agent definition file/version; pin or hash the definition once and share it
- Clear stale caches of tool definitions (deploy artifacts, hot-reload leftovers) and retry
- If you construct requests by hand, compute the hash with the same toolDefinitionSHA256 helper instead of a hardcoded value
Example fix
// before
const request = { tool: 'search', params, toolDefinitionSha256: OLD_HASH };
// after
const tool = definition.tools.find((t) => t.name === 'search');
const request = { tool: tool.name, params, toolDefinitionSha256: toolDefinitionSHA256(tool) }; Defensive patterns
Strategy: validation
Validate before calling
const tool = definition.tools.find((t) => t.name === request.tool);
if (!tool || tool.runtime?.kind === 'subagent') throw new Error('unknown tool');
if (toolDefinitionSHA256(tool) !== request.toolDefinitionSha256) {
throw new Error('stale tool definition hash — rebuild the request from the current definition');
} Type guard
function isFreshToolDefinition(tool, expectedSha) {
return typeof tool === 'object' && tool !== null && toolDefinitionSHA256(tool) === expectedSha;
} Try / catch
try {
const result = await runSandboxTool(request);
} catch (error) {
if (error.message === 'cave_sandbox_tool_definition_mismatch') {
request = rebuildRequestFromCurrentDefinition(request.tool, request.params);
// retry once with the fresh hash
}
} Prevention
- Always compute toolDefinitionSha256 with the same toolDefinitionSHA256 helper the worker uses
- Never cache tool definition hashes across definition edits or deploys
- Rebuild requests after any hot-reload of the agent definition
- Pin the agent definition version so parent and worker agree
When it happens
Trigger: Calling runToolRequest/requestTool where request.tool resolves to exactly one tool (not a subagent) but toolDefinitionSHA256(selected) !== request.toolDefinitionSha256 — i.e. the definition was edited/regenerated after the request's hash was computed, or the request was built against a different agent definition.
Common situations: Editing a tool's description, parameters schema, or execute wiring while old in-flight/subagent requests still carry the old hash; caching tool definitions across deploys; hot-reloading the agent definition while a sandbox request is queued; building the request manually with a hand-copied or wrong hash.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- cave_sandbox_definition_mismatch
- cave_sandbox_side_effect_denied
- integration backup hash mismatch
- proposalrun: seq row_hash mismatch (tampered)
- AutoGen tools and workbench are mutually exclusive
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/786815d9f5d2e6c0.
Report an issue: GitHub.
Appendix: 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 3ee70a1026)