{"record":{"id":"100f614dc0e714a7","repo":"JuliusBrussee/caveman","slug":"cave-stale-lock-dev-snapshot","errorCode":null,"errorMessage":"cave_stale_lock:dev_snapshot","messagePattern":"cave_stale_lock:dev_snapshot","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/cli.ts","lineNumber":1057,"sourceCode":"  const sourceSha256 = await sourceGraphSHA256(root, sourceFiles);\n  return { config, agent, evals, sourceSha256 };\n}\n\nasync function validLockIdentity(\n  root: string,\n  entry: string,\n  expectedAgent?: AgentDefinition,\n  beforeSourceHash?: Parameters<typeof loadBuildInputs>[2],\n): Promise<CaveBuildLock | undefined> {\n  try {\n    const lock = await readLock(root);\n    const loaded = await loadBuildInputs(root, \"caveman.config.ts\", beforeSourceHash);\n    if (resolve(root, loaded.config.entry) !== resolve(root, entry)) {\n      throw new Error(\"cave_stale_lock:entry\");\n    }\n    if (expectedAgent !== undefined &&\n        agentDefinitionSHA256(loaded.agent) !== agentDefinitionSHA256(expectedAgent)) {\n      throw new Error(\"cave_stale_lock:dev_snapshot\");\n    }\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: await transformRegistrySHA256(),\n      catalogSha256: CATALOG_SHA256,\n    });\n    if (!checked.valid) throw new Error(`cave_stale_lock:${checked.stale.join(\",\")}: run npm run build to relock`);\n    return lock;\n  } catch (error) {","sourceCodeStart":1039,"sourceCodeEnd":1075,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/cli.ts#L1039-L1075","documentation":"Thrown inside `validLockIdentity` when an expected `AgentDefinition` was supplied and its `agentDefinitionSHA256` differs from the definition loaded from the lock's config entry. This is the dev-snapshot guard: the lock was minted against an agent definition that no longer matches the in-memory definition the caller is about to run, so lock identity (models, plan, context graph) cannot be trusted for it.","triggerScenarios":"The dev path calls `validLockIdentity(root, entry, expectedAgent)` after the agent module was hot-reloaded or re-imported with changes; any edit to the agent definition (prompt text, tools, subagents, context sources) between `npm run build` and the dev run changes the hash and trips this guard.","commonSituations":"Editing `src/agent.ts` while a dev server/watcher holds a previously built lock; HMR re-importing the entry via `importFresh` (the cache-busting query) so a stale lock is compared against fresh code; teammate commits a rebuilt lock but you still run an older working tree.","solutions":["Run `npm run build` again after any change to the agent definition so the lock's agent digest matches.","If a watcher keeps tripping it, configure the watcher to rebuild (relock) on agent-file change rather than only restarting.","Verify you are not accidentally passing a different AgentDefinition object than the one your config entry exports."],"exampleFix":"# before\nvim src/agent.ts   # edit tools\nnpm run dev         # Error: cave_stale_lock:dev_snapshot\n\n# after\nvim src/agent.ts\nnpm run build && npm run dev","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await dev(args);\n} catch (error) {\n  if (error instanceof Error && error.message === \"cave_stale_lock:dev_snapshot\") {\n    // agent definition changed since the last build: run npm run build, then retry\n  } else throw error;\n}","preventionTips":["Rebuild after every edit to the agent entry or any file feeding the definition digest.","In watch mode, trigger relock on change instead of only reloading modules.","Never mix a freshly imported agent with an old lock in the same process."],"tags":["lock","drift","dev","hot-reload"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}