JuliusBrussee/caveman · error · Error

cave_stale_lock:registration

Error message

cave_stale_lock:registration

What it means

Before registering, the CLI re-validates .caveman/agent.lock.json against freshly loaded build inputs: validLockIdentity(root, entry) must succeed AND its build_sha256 must equal the one in the lock read earlier. Failure means the lock is stale relative to current sources/config — registering it would publish a build hash that no longer matches the code, so registration is refused with the cave_stale_lock:registration scope tag.

Source

Thrown at packages/agent/src/cli.ts:475

      available: Boolean(process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY),
    };
  }
  return { name: `credential for ${provider || "unknown provider"}`, available: false };
}

async function register(_args: string[]): Promise<void> {
  const root = process.cwd();
  const controlURL = process.env.CAVE_CONTROL_URL?.replace(/\/+$/, "");
  const token = process.env.CAVE_TOKEN ?? process.env.CAVE_API_TOKEN;
  const projectID = process.env.CAVE_PROJECT_ID;
  if (!controlURL || !token || !projectID) {
    throw new Error("register requires CAVE_CONTROL_URL, CAVE_TOKEN, and CAVE_PROJECT_ID");
  }
  const lock = await readLock(root);
  const loaded = await loadBuildInputs(root, "caveman.config.ts");
  const checked = await validLockIdentity(root, loaded.config.entry);
  if (!checked || checked.build_sha256 !== lock.build_sha256) {
    throw new Error("cave_stale_lock:registration");
  }
  const response = await fetch(`${controlURL}/api/v1/projects/${encodeURIComponent(projectID)}/agent-builds`, {
    method: "POST",
    headers: {
      authorization: `Bearer ${token}`,
      "content-type": "application/json",
    },
    body: JSON.stringify({
      agent_slug: lock.agent_id,
      build_sha256: lock.build_sha256,
      plan_sha256: lock.plan_sha256,
      source_sha256: lock.source_sha256,
      eval_suite_sha256: lock.eval_suite_sha256,
      catalog_sha256: lock.catalog_sha256,
      transform_registry_sha256: lock.runtime.transform_registry_sha256,
      harness: lock.harness.id,
      adapter_version: lock.harness.adapter_version,
      upstream_version: lock.harness.upstream_version,

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Rebuild to refresh the lock: caveman-agent build, then caveman-agent register.
  2. If register keeps failing, run caveman-agent doctor to see the lock check state and confirm which inputs drifted.
  3. Treat the lock as an artifact: commit it at the same commit as the sources it hashes, and never edit sources between build and register.

Example fix

# before
caveman-agent build
# (edit src/agent.ts)
caveman-agent register # throws cave_stale_lock:registration

# after
caveman-agent build
caveman-agent register # no edits in between
Defensive patterns

Strategy: validation

Validate before calling

async function lockMatchesCurrentBuild(root: string): Promise<boolean> {
  const loaded = await loadBuildInputs(root, "caveman.config.ts");
  const lock = await readLock(root);
  const checked = await validLockIdentity(root, loaded.config.entry);
  return Boolean(checked) && checked.build_sha256 === lock.build_sha256;
}

Try / catch

try {
  await register(args);
} catch (error) {
  if (error instanceof Error && error.message === "cave_stale_lock:registration") {
    // deterministic fix: rebuild to refresh the lock, then register once
    await build(["caveman.config.ts"]);
    return register(args);
  }
  throw error;
}

Prevention

When it happens

Trigger: Editing any build input (entry, caveman.config.ts, eval files, source graph) after `caveman-agent build` and then running register; no lock at all (validLockIdentity falsy); or the lock being regenerated between readLock and validation (sha mismatch).

Common situations: Build → commit/push → teammate pulls → sources move ahead of the committed lock; CI checkout where .caveman/agent.lock.json is cached but the repo advanced; local hotfix edit forgotten before register.

Related errors


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