{"record":{"id":"ceafa27d955d8ede","repo":"JuliusBrussee/caveman","slug":"cave-stale-lock-checked-stale-join-run-np","errorCode":null,"errorMessage":"cave_stale_lock:${checked.stale.join(\",\")}: run npm run build to relock","messagePattern":"cave_stale_lock:(.+?): run npm run build to relock","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/cli.ts","lineNumber":959,"sourceCode":"    throw error;\n  }\n  const transformRegistrySha256 = await transformRegistrySHA256();\n  const checked = checkLock(lock, {\n    sourceSha256: loaded.sourceSha256,\n    agentDefinitionSha256: agentDefinitionSHA256(loaded.agent),\n    contextIRSha256: contextIRSHA256(await lowerBuildContext(\n      root,\n      loaded.agent,\n    ).then((value) => value.ir)),\n    evalSuiteSha256: sha256(stableStringify(loaded.evals.filter((item) => item.approved && item.required))),\n    runtimeVersion: FRAMEWORK_VERSION,\n    adapterVersion: PI_ADAPTER_VERSION,\n    upstreamVersion: PI_UPSTREAM_VERSION,\n    transformRegistrySha256,\n    catalogSha256: CATALOG_SHA256,\n  });\n  if (!checked.valid) {\n    throw new Error(`cave_stale_lock:${checked.stale.join(\",\")}: run npm run build to relock`);\n  }\n  process.stdout.write([\n    `lock valid: ${lock.build_sha256}`,\n    `plan: ${lock.selected_plan_id}`,\n    `catalog cost/task: $${lock.evidence.catalog_cost_usd_per_task.toFixed(6)}`,\n    \"local evidence: passed (estimate only)\",\n    \"provider savings: not claimed\",\n    \"\",\n  ].join(\"\\n\"));\n}\n\ntype LoadedBuildInputs = {\n  config: BuildConfig;\n  agent: AgentDefinition;\n  evals: EvalDefinition[];\n  sourceSha256: string;\n};\n","sourceCodeStart":941,"sourceCodeEnd":977,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/cli.ts#L941-L977","documentation":"Thrown by `check` when `checkLock` reports the recorded digests no longer match reality. The lock pins source sha256, agent definition sha256, Context IR sha256, approved+required eval suite sha256, framework/Pi-adapter/upstream versions, transform registry sha256, and the pricing catalog sha256 (`CATALOG_SHA256`). Any drift field is listed comma-separated in the message; the fix is always to rebuild so the lock is re-minted against current inputs.","triggerScenarios":"`caveman check` after editing any source file the source graph reaches, changing the agent entry, editing an approved required eval, upgrading @caveman-ai/agent or the pinned Pi version, updating the engine registry via `caveman setup`, or a catalog regeneration changing CATALOG_SHA256.","commonSituations":"Pulling a branch that bumped dependencies; `pnpm install` pulling a newer transitive package; re-running the catalog generator; engine registry refreshed on a teammate's machine committed alongside source changes; forgetting that lock drift includes version pins, not just code edits.","solutions":["Run `npm run build` to relock against the current sources, versions, registry, and catalog.","If the drift field is `transformRegistrySha256` or `catalogSha256`, re-run `caveman setup` / the catalog generator first so the rebuild pins reproducible values.","If drift appears with zero edits, suspect version skew: confirm FRAMEWORK_VERSION/PI_UPSTREAM_VERSION match the installed package (`caveman doctor` reports these).","Commit the regenerated `.caveman/agent.lock.json` together with the source changes that caused the drift."],"exampleFix":"# before\nnpm run check\n# Error: cave_stale_lock:source_sha256,eval_suite_sha256: run npm run build to relock\n\n# after\nnpm run build && npm run check","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await check(args);\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith(\"cave_stale_lock:\")) {\n    const stale = error.message.split(\":\")[1]?.split(\",\") ?? [];\n    // map each field to its trigger (source/eval -> rebuild; registry -> caveman setup; versions -> align deps)\n  } else throw error;\n}","preventionTips":["Chain build before check in every workflow that may have edited sources.","Commit the lock together with the source changes that drifted it.","Treat dependency upgrades as lock-drift events: rebuild immediately after install."],"tags":["build","lock","drift","cli"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}