JuliusBrussee/caveman · error · Error
cave_stale_lock:entry
Error message
cave_stale_lock:entry
What it means
Thrown inside `validLockIdentity` (the dev-path lock validator). It reads the existing lock, re-loads build inputs from `caveman.config.ts`, and requires the config's `entry` to resolve to the same absolute path as the `entry` argument the caller passed. A mismatch means the lock on disk was minted for a different agent entry file than the one the runtime is about to execute, so the lock is stale for this entry.
Source
Thrown at packages/agent/src/cli.ts:1053
} catch (error) {
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
}
}
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,View on GitHub (pinned to 27d5a3981a)
Solutions
- Make the entry passed to the runtime match `caveman.config.ts`'s `entry` exactly (same file, resolved against the same root).
- If you deliberately changed the entry, run `npm run build` so the lock is re-minted for the new entry.
- For multiple agents, give each its own project root/config so locks don't collide.
- Run the CLI from the project root so path resolution matches the build-time root.
Example fix
// before: config says one entry, runtime passes another
// caveman.config.ts -> entry: "src/agent.ts"
await runtime.run("./src/agent-v2.ts");
// after
// caveman.config.ts -> entry: "src/agent-v2.ts"
await npm run build; // relock
await runtime.run("./src/agent-v2.ts"); Defensive patterns
Strategy: validation
Validate before calling
import { resolve } from "node:path";
function entryMatches(root: string, configEntry: string, runtimeEntry: string): boolean {
return resolve(root, configEntry) === resolve(root, runtimeEntry);
} Try / catch
try {
await dev(args);
} catch (error) {
if (error instanceof Error && error.message === "cave_stale_lock:entry") {
// align the runtime entry with caveman.config.ts entry, then npm run build
} else throw error;
} Prevention
- Single source of truth: read the entry from caveman.config.ts rather than passing a second copy.
- Rebuild immediately after renaming or switching the agent entry file.
- Run commands from the project root so resolution matches build time.
When it happens
Trigger: Running the dev/runtime path with an entry path different from `config.entry` recorded when the lock was built — e.g. renamed or moved the agent entry file, passed an absolute path where the config uses a relative one pointing elsewhere, or switched agents by editing `caveman.config.ts` without rebuilding.
Common situations: Renaming `src/agent.ts` to `src/main.ts` and updating only the caller, not the config; multi-agent repositories where two entries share one `.caveman/`; a worktree or symlink layout making `resolve(root, entry)` land on a different real file; changing `root` (running from a different directory).
Related errors
- cave_stale_lock:dev_snapshot
- cave_stale_lock:${checked.stale.join(",")}: run npm run buil
- cave_budget_denomination_ambiguous
- cave_budget_max_invalid
- cave_budget_output_floor_invalid
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/1864dd2fac8d9277.
Report an issue: GitHub.