{"record":{"id":"786815d9f5d2e6c0","repo":"JuliusBrussee/caveman","slug":"cave-sandbox-tool-definition-mismatch","errorCode":"cave_sandbox_tool_definition_mismatch","errorMessage":"cave_sandbox_tool_definition_mismatch","messagePattern":"cave_sandbox_tool_definition_mismatch","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/tool-worker.ts","lineNumber":131,"sourceCode":"    const delegated = definition.tools.filter((item) =>\n      item.name === name && item.runtime?.kind === \"subagent\"\n    );\n    if (delegated.length !== 1) throw new Error(\"cave_sandbox_unknown_subagent\");\n    const child = delegated[0]!.runtime!.definition as AgentDefinition;\n    if (!child || child.kind !== \"agent\") {\n      throw new Error(\"cave_sandbox_subagent_definition_invalid\");\n    }\n    if (visited.has(child)) throw new Error(\"cave_sandbox_subagent_cycle\");\n    visited.add(child);\n    definition = child;\n  }\n  const selectedTools = definition.tools.filter((item) => item.name === request.tool);\n  if (selectedTools.length !== 1 || selectedTools[0]!.runtime?.kind === \"subagent\") {\n    throw new Error(\"cave_sandbox_unknown_tool\");\n  }\n  const selected = selectedTools[0]!;\n  if (toolDefinitionSHA256(selected) !== request.toolDefinitionSha256) {\n    throw new Error(\"cave_sandbox_tool_definition_mismatch\");\n  }\n  if (selected.effect !== \"read\" && request.allowSideEffects !== true) {\n    throw new Error(\"cave_sandbox_side_effect_denied\");\n  }\n  const value = await selected.execute(request.params as never, AbortSignal.timeout(selected.timeoutMs));\n  writeResult({ ok: true, value });\n} catch (error) {\n  writeResult({ ok: false, code: failureCode(error) });\n}\n","sourceCodeStart":113,"sourceCodeEnd":141,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/tool-worker.ts#L113-L141","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ntool({ name: \"fetch\", timeoutMs: Date.now() % 60000, ... }) // unstable hash input\n\n// after\ntool({ name: \"fetch\", timeoutMs: 30_000, ... }) // stable hash input","handlingStrategy":"validation","validationCode":"import { toolDefinitionSHA256 } from \"@caveman-ai/agent/build.js\";\nconst selected = def.tools.find((t) => t.name === request.tool)!;\nif (toolDefinitionSHA256(selected) !== request.toolDefinitionSha256) throw new Error(\"tool digest drift; re-derive before spawn\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["sandbox","integrity","sha256","cave"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}