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
- Rebuild the build lock for the agent being executed.
- Pass the correct build lock corresponding to input.agentId.
- Omit agentId only if the lock intentionally is not agent-bound (and that is acceptable in your flow).
- 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
- Key build locks by agent id and look them up per agent, never share one lock across agents.
- Keep agent ids stable across runs when caching locks.
- Purge cached locks when agent definitions are renamed or recreated.
- Log lock.agent_id and requested agentId together on failure for fast diagnosis.
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
- cave_harness_build_mismatch
- cave_harness_context_ir_mismatch
- cave_harness_plan_digest_mismatch
- cave_harness_plan_mismatch
- cave_claude_terminal_${result?.subtype ?? "missing"}
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)