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

  1. Rebuild the build lock using the exact contextIR that will be executed.
  2. Pass the same contextIR (byte-identical after wire serialization) used at lock time.
  3. Remove non-deterministic fields (timestamps, random ids) from the context IR or make them deterministic for locked runs.
  4. 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

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


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)