JuliusBrussee/caveman · error
cave_harness_context_ir_mismatch
cave_harness_context_ir_mismatch
Error message
cave_harness_context_ir_mismatch
What it means
The kernel serializes the runtime context IR to its wire form and compares its SHA-256 against build.context_ir_sha256 in the lock. It throws when the context IR differs from what was locked, ensuring the model sees exactly the locked context during a locked harness execution.
Solutions
- Rebuild the build lock using the exact contextIR that will be executed.
- Pass the same contextIR (byte-identical after wire serialization) used at lock time.
- Remove non-deterministic fields (timestamps, random ids) from the context IR or make them deterministic for locked runs.
- Verify both sides use the same contextIRToWire serialization version.
Example fix
// before
const contextIR = buildContextIR({ now: new Date() }); // lock built earlier, different now
await prepared({ build: lock, contextIR });
// after
const contextIR = buildContextIR({ now: lock.context_ir.now });
await prepared({ build: lock, contextIR }); Defensive patterns
Strategy: validation
Validate before calling
import { createHash } from "node:crypto";
const digest = createHash("sha256").update(stableStringify(contextIRToWire(contextIR))).digest("hex");
if (digest !== lock.context_ir_sha256) {
lock = await buildCaveBuildLock({ plan, contextIR });
} Type guard
function contextIRMatchesLock(contextIR: unknown, lock: { context_ir_sha256: string }): boolean {
return sha256(stableStringify(contextIRToWire(contextIR))) === lock.context_ir_sha256;
} Try / catch
try {
await prepared({ build: lock, contextIR, ... });
} catch (err) {
if (err instanceof Error && err.message === "cave_harness_context_ir_mismatch") {
const fresh = await buildCaveBuildLock({ plan, contextIR });
return prepared({ build: fresh, contextIR, ... });
}
throw err;
} Prevention
- Build the lock and execute in the same step so context cannot drift.
- Strip or pin non-deterministic context fields (timestamps, ids) for locked runs.
- Run compaction/trimming of context before lock creation, not after.
- Keep contextIRToWire serialization version identical on both sides of the lock.
When it happens
Trigger: Calling prepared or streamAgentInternal with a contextIR whose wire serialization hash differs from build.context_ir_sha256 — any change to context contents, ordering, or IR schema version triggers it.
Common situations: Dynamic context (timestamps, tool results, env) differing between lock build and execution; a context compaction or trimming step running before execution; IR schema/serialization change after an upgrade; building the lock in one process and executing with slightly different context in another.
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_harness_plan_digest_mismatch
- cave_harness_agent_mismatch
- cave_harness_build_mismatch
- cave_harness_plan_mismatch
- adapter-specific build_sha256 values must differ
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/f0dc4542e81fbf53.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/execution-kernel.ts:90
const build = parseCaveBuildLock(input.build);
if (build.harness.id !== input.harness ||
build.harness.adapter_version !== input.adapterVersion ||
build.harness.upstream_version !== input.upstreamVersion) {
throw new Error("cave_harness_build_mismatch");
}
if (input.agentId !== undefined && build.agent_id !== input.agentId) {
throw new Error("cave_harness_agent_mismatch");
}
if (stableStringify(input.plan) !== stableStringify(build.selected_plan)) {
throw new Error("cave_harness_plan_mismatch");
}
const planSHA256 = sha256(stableStringify(input.plan));
if (planSHA256 !== build.plan_sha256) {
throw new Error("cave_harness_plan_digest_mismatch");
}
const contextIRSHA256 = sha256(stableStringify(contextIRToWire(input.contextIR)));
if (contextIRSHA256 !== build.context_ir_sha256) {
throw new Error("cave_harness_context_ir_mismatch");
}
const [provider, ...modelParts] = input.plan.model.split("/");
const model = modelParts.join("/");
if (!provider || !model) throw new Error("cave_harness_model_invalid");
return Object.freeze({
build,
plan: build.selected_plan,
planSHA256,
contextIRSHA256,
provider,
model,
});
}
export interface ProviderUsageEvidence {
provider: string;
model: string;
inputTokens: number;View on GitHub (pinned to 3ee70a1026)