JuliusBrussee/caveman · error · Error
cave_stale_lock:dev_snapshot
Error message
cave_stale_lock:dev_snapshot
What it means
Inside `validLockIdentity`, when the caller supplies `expectedAgent`, the freshly loaded agent definition must hash identically (`agentDefinitionSHA256(loaded.agent) !== agentDefinitionSHA256(expectedAgent)` → throw). The in-memory dev snapshot of the agent no longer matches the definition that the current config/entry produce — typically the agent was edited after the snapshot was taken.
Solutions
- Run `npm run build` to relock, then restart the dev process
- Restart dev so the expected snapshot is reloaded from the current entry
- Avoid editing the entry module between snapshot capture and the locked run
Defensive patterns
Strategy: validation
Validate before calling
// Before a locked dev run, compare the snapshot against a fresh load:
const fresh = await loadAgent(resolve(root, config.entry));
if (agentDefinitionSHA256(fresh) !== agentDefinitionSHA256(expectedAgent)) {
await exec("npm run build"); // definition drifted — relock first
} Try / catch
catch (e) { if (e instanceof Error && e.message === "cave_stale_lock:dev_snapshot") { /* restart dev / rebuild to refresh the snapshot */ } else throw e; } Prevention
- Restart the dev process after every entry-module edit
- Rebuild before any locked run
- Avoid editing the agent definition while a locked run is in flight
When it happens
Trigger: Starting a dev/locked flow with an `expectedAgent` snapshot captured before the entry module was edited (hot reload changed the definition); the config entry now loading a different definition than the dev snapshot holds.
Common situations: Editing the entry file mid-`caveman dev` session; editing the agent definition between `npm run build` and a locked dev run.
Related errors
- cave_stale_lock:entry
- cave_stale_lock: : run npm run build to relock
- cave_harness_agent_mismatch
- cave_harness_build_mismatch
- cave_harness_context_ir_mismatch
AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18).
Data as JSON: /api/errors/100f614dc0e714a7.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/cli.ts:1057
const sourceSha256 = await sourceGraphSHA256(root, sourceFiles);
return { config, agent, evals, sourceSha256 };
}
async function validLockIdentity(
root: string,
entry: string,
expectedAgent?: AgentDefinition,
beforeSourceHash?: Parameters<typeof loadBuildInputs>[2],
): Promise<CaveBuildLock | undefined> {
try {
const lock = await readLock(root);
const loaded = await loadBuildInputs(root, "caveman.config.ts", beforeSourceHash);
if (resolve(root, loaded.config.entry) !== resolve(root, entry)) {
throw new Error("cave_stale_lock:entry");
}
if (expectedAgent !== undefined &&
agentDefinitionSHA256(loaded.agent) !== agentDefinitionSHA256(expectedAgent)) {
throw new Error("cave_stale_lock:dev_snapshot");
}
const checked = checkLock(lock, {
sourceSha256: loaded.sourceSha256,
agentDefinitionSha256: agentDefinitionSHA256(loaded.agent),
contextIRSha256: contextIRSHA256(await lowerBuildContext(
root,
loaded.agent,
).then((value) => value.ir)),
evalSuiteSha256: sha256(stableStringify(loaded.evals.filter((item) => item.approved && item.required))),
runtimeVersion: FRAMEWORK_VERSION,
adapterVersion: PI_ADAPTER_VERSION,
upstreamVersion: PI_UPSTREAM_VERSION,
transformRegistrySha256: await transformRegistrySHA256(),
catalogSha256: CATALOG_SHA256,
});
if (!checked.valid) throw new Error(`cave_stale_lock:${checked.stale.join(",")}: run npm run build to relock`);
return lock;
} catch (error) {View on GitHub (pinned to 766dce6b13)