JuliusBrussee/caveman · error
cave_sandbox_definition_mismatch
cave_sandbox_definition_mismatch
Error message
cave_sandbox_definition_mismatch
What it means
The worker recomputes the sha256 digest of the imported root agent definition and compares it with request.rootDefinitionSha256. A mismatch throws `cave_sandbox_definition_mismatch`. This pins the executed definition to exactly the bytes the parent validated — if the entry module resolves to different definition content at runtime, execution is refused.
Solutions
- Restart or re-run the build so the parent re-hashes the current definition, then retry.
- Make the definition deterministic: no timestamps, random values, or environment reads at module scope.
- Ensure the entry path resolves to the same physical file the parent hashed (avoid path aliases/duplicated packages; check pnpm/npm layout).
- Avoid mutating the definition object after the build hashed it.
Example fix
// before
export default agent(`a-${Date.now()}`).tool(search).build();
// after
export default agent("a").tool(search).build(); Defensive patterns
Strategy: validation
Validate before calling
// Before spawning, verify the on-disk definition still matches the hashed build
const current = agentDefinitionSHA256(importedDefinition);
if (current !== expectedRootDefinitionSha256) {
throw new Error("definition drifted since build; re-run caveman build before invoking");
} Try / catch
try {
await runSandboxed(request);
} catch (err) {
if (err instanceof Error && err.message.includes("cave_sandbox_definition_mismatch")) {
console.error("definition changed under a locked build — restart dev / re-run build");
}
throw err;
} Prevention
- Keep agent definition construction deterministic: no Date.now(), Math.random(), or env reads at module scope.
- Do not edit agent source files while a locked run is in flight; restart dev after edits.
- Avoid path aliases and duplicated package copies so the entry resolves to the hashed file.
- Never mutate a definition object after the build computed its digest.
When it happens
Trigger: The entry module's definition differs from what the parent hashed: the file changed on disk between hashing and spawn (hot reload/edit), the entry resolves to a different file (path alias, duplicate package install), or the definition is built nondeterministically (timestamps, random ids, env-dependent fields).
Common situations: Editing agent source while a dev run is in flight; monorepo resolution picking a different copy of the definition module than the one hashed; definition construction embedding `Date.now()`, random ids, or reading mutable env/config at module load.
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_tool_definition_mismatch
- invalid_recovery
- cave_harness_incomplete_evidence
- cave_host_sandbox_lock_ineligible
- cave_host_sandbox_nested_under_required
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/c7b0e34bf79394fe.
Report an issue: GitHub.
Appendix: 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 3ee70a1026)