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

  1. Make the entry passed to the runtime match `caveman.config.ts`'s `entry` exactly (same file, resolved against the same root).
  2. If you deliberately changed the entry, run `npm run build` so the lock is re-minted for the new entry.
  3. For multiple agents, give each its own project root/config so locks don't collide.
  4. 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

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


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/1864dd2fac8d9277. Report an issue: GitHub.