JuliusBrussee/caveman · error

cave_harness_agent_mismatch

cave_harness_agent_mismatch

Error message

cave_harness_agent_mismatch

What it means

prepareLockedHarnessExecution checks that the build lock's agent_id matches the agent being executed, but only when an agentId is supplied. It throws when executing a locked build against a different agent than the one the build was prepared for. This binds a locked build to a specific agent definition.

Solutions

  1. Rebuild the build lock for the agent being executed.
  2. Pass the correct build lock corresponding to input.agentId.
  3. Omit agentId only if the lock intentionally is not agent-bound (and that is acceptable in your flow).
  4. Ensure agent ids are stable and not regenerated per run if locks are cached.

Example fix

// before
await streamAgentInternal({ build: lockForAgentA, agentId: "agent-b", ... });
// after
const lock = await buildCaveBuildLock({ agentId: "agent-b" });
await streamAgentInternal({ build: lock, agentId: "agent-b", ... });
Defensive patterns

Strategy: validation

Validate before calling

if (agentId !== undefined && lock.agent_id !== agentId) {
  lock = await buildCaveBuildLock({ agentId });
}

Type guard

function lockIsForAgent(lock: { agent_id?: string }, agentId: string | undefined): boolean {
  return agentId === undefined || lock.agent_id === agentId;
}

Try / catch

try {
  await streamAgentInternal({ build: lock, agentId, ... });
} catch (err) {
  if (err instanceof Error && err.message === "cave_harness_agent_mismatch") {
    const fresh = await buildCaveBuildLock({ agentId });
    return streamAgentInternal({ build: fresh, agentId, ... });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling prepared or streamAgentInternal with input.agentId set to an agent id different from build.agent_id, typically after switching agent definitions while reusing a cached build lock.

Common situations: Renaming or recreating an agent so its id changed while an old lock persisted; running multiple agents but passing the wrong lock; a lock generated in CI for agent A reused locally for agent B.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/b455c880ee18c7e2. Report an issue: GitHub.

Appendix: source

Thrown at packages/agent/src/execution-kernel.ts:79

}

export function prepareLockedHarnessExecution(input: {
  build: CaveBuildLock;
  harness: string;
  adapterVersion: string;
  upstreamVersion: string;
  agentId?: string;
  contextIR: ContextIR;
  plan: CavePlan;
}): LockedHarnessPreparation {
  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,

View on GitHub (pinned to 3ee70a1026)