{"record":{"id":"40ab9feae62bb15c","repo":"JuliusBrussee/caveman","slug":"cave-harness-build-mismatch","errorCode":"cave_harness_build_mismatch","errorMessage":"cave_harness_build_mismatch","messagePattern":"cave_harness_build_mismatch","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/execution-kernel.ts","lineNumber":76,"sourceCode":"      selected.reasoning !== expectedReasoning) {\n    throw new Error(\"cave_execution_plan_selection_mismatch\");\n  }\n}\n\nexport function prepareLockedHarnessExecution(input: {\n  build: CaveBuildLock;\n  harness: string;\n  adapterVersion: string;\n  upstreamVersion: string;\n  agentId?: string;\n  contextIR: ContextIR;\n  plan: CavePlan;\n}): LockedHarnessPreparation {\n  const build = parseCaveBuildLock(input.build);\n  if (build.harness.id !== input.harness ||\n      build.harness.adapter_version !== input.adapterVersion ||\n      build.harness.upstream_version !== input.upstreamVersion) {\n    throw new Error(\"cave_harness_build_mismatch\");\n  }\n  if (input.agentId !== undefined && build.agent_id !== input.agentId) {\n    throw new Error(\"cave_harness_agent_mismatch\");\n  }\n  if (stableStringify(input.plan) !== stableStringify(build.selected_plan)) {\n    throw new Error(\"cave_harness_plan_mismatch\");\n  }\n  const planSHA256 = sha256(stableStringify(input.plan));\n  if (planSHA256 !== build.plan_sha256) {\n    throw new Error(\"cave_harness_plan_digest_mismatch\");\n  }\n  const contextIRSHA256 = sha256(stableStringify(contextIRToWire(input.contextIR)));\n  if (contextIRSHA256 !== build.context_ir_sha256) {\n    throw new Error(\"cave_harness_context_ir_mismatch\");\n  }\n  const [provider, ...modelParts] = input.plan.model.split(\"/\");\n  const model = modelParts.join(\"/\");\n  if (!provider || !model) throw new Error(\"cave_harness_model_invalid\");","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/execution-kernel.ts#L58-L94","documentation":"Thrown while preparing a locked harness (packages/agent/src/execution-kernel.ts:76): the CaveBuildLock's harness identity (harness.id, harness.adapter_version, harness.upstream_version) does not match the harness/adapter/upstream versions supplied at execution time. Locked execution is exact-pinned, so any drift between the lock and the actually-loaded runtime is rejected before spend.","triggerScenarios":"Executing a locked build whose lock file was produced for a different harness id (e.g. pi vs a Vercel/Eve/Mastra adapter) or different adapter/upstream versions than the ones currently installed/registered.","commonSituations":"Upgrading @caveman-ai/agent or the upstream SDK after the lock was built; switching harness/adapter between build and run; running a lock produced on another machine/CI with different pinned versions; stale lock file committed to the repo.","solutions":["Rebuild the lock (re-run the build/compile step) so harness/adapter/upstream versions in the lock match the current environment.","Check that the harness identifier passed to the execution call is the same one the lock was built for.","Pin the exact same package versions (agent package, adapter, upstream SDK) that were present at build time before re-running."],"exampleFix":"# before\n# lock built with agent 1.2.0 / upstream pinned A, then packages upgraded\ncaveman build && caveman run --lock cave-build.lock # -> cave_harness_build_mismatch\n\n# after\ngit restore package.json pnpm-lock.yaml # restore exact build-time versions\ncaveman build # regenerate lock against current pins\ncaveman run --lock cave-build.lock","handlingStrategy":"try-catch","validationCode":"import { FRAMEWORK_VERSION, ADAPTER_VERSION, UPSTREAM_VERSION } from \"@caveman-ai/agent\";\n// before running a locked build, compare recorded lock identity with the current runtime:\nconst lock = parseCaveBuildLock(rawLock);\nconst drift = lock.harness.id !== harnessId ||\n  lock.harness.adapter_version !== ADAPTER_VERSION ||\n  lock.harness.upstream_version !== UPSTREAM_VERSION;\nif (drift) await rebuildLock();","typeGuard":null,"tryCatchPattern":"try {\n  prepareLockedHarness(input);\n} catch (e) {\n  if (e instanceof Error && e.message === \"cave_harness_build_mismatch\") {\n    // environment drifted from the lock: rebuild, don't retry as-is\n    await rebuildLock(input);\n  } else throw e;\n}","preventionTips":["Regenerate locks whenever agent/adapter/upstream versions change.","Commit the lock and lockfile versions together so CI restores both or neither.","Run `caveman doctor` before locked runs to detect lock drift early."],"tags":["lockfile","version-drift","harness","reproducibility"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}