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

  1. Regenerate the request (re-derive request.toolDefinitionSha256) from the same definition object/version currently loaded in the worker
  2. Ensure the parent and worker load the identical agent definition file/version; pin or hash the definition once and share it
  3. Clear stale caches of tool definitions (deploy artifacts, hot-reload leftovers) and retry
  4. 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

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


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)