JuliusBrussee/caveman · error
cave_sandbox_definition_mismatch
cave_sandbox_definition_mismatch
Error message
cave_sandbox_definition_mismatch
What it means
The sandbox worker recomputes `agentDefinitionSHA256(definition)` over the imported root agent and compares it to `request.rootDefinitionSha256` sent by the parent. A mismatch means the module the worker loaded is not byte-for-byte the definition the parent inspected when it computed the hash — an integrity fail-closed check against definition drift between parent and sandbox.
Source
Thrown at packages/agent/src/tool-worker.ts:109
request.agentPath.some((item) => typeof item !== "string" ||
!/^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test(item)) ||
typeof request.rootDefinitionSha256 !== "string" ||
!/^[a-f0-9]{64}$/.test(request.rootDefinitionSha256) ||
typeof request.toolDefinitionSha256 !== "string" ||
!/^[a-f0-9]{64}$/.test(request.toolDefinitionSha256) ||
typeof request.tool !== "string" ||
!/^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/.test(request.tool) ||
typeof request.allowSideEffects !== "boolean" ||
typeof request.allowNetwork !== "boolean") {
throw new Error("cave_sandbox_request_invalid");
}
if (request.allowNetwork !== true) installNetworkDeny();
const imported = await import(request.entry) as { default?: AgentDefinition; agent?: AgentDefinition };
let definition = imported.default ?? imported.agent;
if (!definition || definition.kind !== "agent") throw new Error("cave_sandbox_agent_export_missing");
validateAgentGraph(definition);
if (agentDefinitionSHA256(definition) !== request.rootDefinitionSha256) {
throw new Error("cave_sandbox_definition_mismatch");
}
const visited = new Set<AgentDefinition>([definition]);
for (const name of request.agentPath) {
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");View on GitHub (pinned to 27d5a3981a)
Solutions
- Make the AgentDefinition deterministic: no Date.now()/Math.random()/process.env values inside the definition object.
- Re-derive and pass the digest from the exact same staged copy the worker will import (same snapshot for digest and import).
- Restart the dev session after editing agent modules so parent and worker agree on one immutable snapshot.
- Verify parent and worker run the same package version — print agentDefinitionSHA256(definition) in both processes and diff.
Example fix
// before
const definition = { ...base, createdAt: Date.now() }; // hash differs per process
// after
const definition = { ...base, createdAt: FIXED_BUILD_TIMESTAMP }; // stable across parent and worker Defensive patterns
Strategy: validation
Validate before calling
import { agentDefinitionSHA256 } from "@caveman-ai/agent/build.js";
const def = (await import(entry)).default;
const digest = agentDefinitionSHA256(def);
if (digest !== request.rootDefinitionSha256) throw new Error("refusing to spawn: digest drift"); Type guard
function isStableDefinition(def: object): boolean {
return agentDefinitionSHA256(def) === agentDefinitionSHA256(structuredClone(def));
} Prevention
- Keep definitions free of Date.now()/random/env values.
- Hash and import from the same immutable staged snapshot in required-sandbox runs.
- Restart dev sessions after editing agent sources.
When it happens
Trigger: Parent computes the digest from one version of the source graph, then the worker imports a different version: hot-reloaded dev server rewrote the entry between digest and spawn; the staged per-run copy of the source graph diverged from the parent snapshot; nondeterministic definition construction (Date.now(), random ids, env-dependent fields) baked into the definition object.
Common situations: Editing agent files while a dev session is mid-run; a build/staging race in programmatic required-sandbox runs that copy the source graph; definitions that embed unstable values (timestamps, uuids) so their hash changes every process; mismatched package versions between parent and worker.
Related errors
- cave_sandbox_tool_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/c7b0e34bf79394fe.
Report an issue: GitHub.