JuliusBrussee/caveman · error · Error

cave_harness_agent_mismatch

cave_harness_agent_mismatch

Error message

cave_harness_agent_mismatch

What it means

Thrown while preparing a locked harness (packages/agent/src/execution-kernel.ts:79): an agentId was supplied for the execution but it differs from the build.agent_id recorded in the CaveBuildLock. A lock is bound to one specific agent definition; running it against another agent's id is rejected.

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 27d5a3981a)

Solutions

  1. Regenerate the lock for the agent you are actually running (each agent gets its own lock).
  2. Verify the agent id string passed at run time matches the id in agent({...}) used at build time (ids are lowercase, max 96 chars).
  3. If the agent was renamed, rebuild all locks that referenced the old id.

Example fix

// before
const lock = loadLock("cave-build.json"); // built for agent "researcher"
prepareLockedHarness({ build: lock, agentId: "writer", /* ... */ });

// after
const lockForWriter = buildFor(agentDefinition("writer"));
prepareLockedHarness({ build: lockForWriter, agentId: "writer", /* ... */ });
Defensive patterns

Strategy: validation

Validate before calling

const lock = parseCaveBuildLock(rawLock);
if (input.agentId !== undefined && lock.agent_id !== input.agentId) {
  throw new Error(`lock belongs to agent '${lock.agent_id}', got '${input.agentId}'`);
}

Try / catch

try { prepareLockedHarness(input); }
catch (e) {
  if (e instanceof Error && e.message === "cave_harness_agent_mismatch") {
    // fetch/build the lock for THIS agent id, then retry once
    input = { ...input, build: await lockForAgent(input.agentId!) };
    prepareLockedHarness(input);
  } else throw e;
}

Prevention

When it happens

Trigger: Passing RunOptions/execution input with agentId set to a different agent than the one the lock was compiled from — e.g., reusing one agent's lock file for a sibling agent in the same project, or renaming an agent id after the lock was built.

Common situations: Multiple agents in one project sharing a lock path; renaming an agent's id in code without rebuilding; copy-pasting run code between agents while keeping the same lock reference.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/b455c880ee18c7e2. Report an issue: GitHub.