{"record":{"id":"4f86f516ea0cede0","repo":"JuliusBrussee/caveman","slug":"cave-stale-lock","errorCode":"cave_stale_lock","errorMessage":"cave_stale_lock:registration","messagePattern":"cave_stale_lock:registration","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/cli.ts","lineNumber":475,"sourceCode":"      available: Boolean(process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY),\n    };\n  }\n  return { name: `credential for ${provider || \"unknown provider\"}`, available: false };\n}\n\nasync function register(_args: string[]): Promise<void> {\n  const root = process.cwd();\n  const controlURL = process.env.CAVE_CONTROL_URL?.replace(/\\/+$/, \"\");\n  const token = process.env.CAVE_TOKEN ?? process.env.CAVE_API_TOKEN;\n  const projectID = process.env.CAVE_PROJECT_ID;\n  if (!controlURL || !token || !projectID) {\n    throw new Error(\"register requires CAVE_CONTROL_URL, CAVE_TOKEN, and CAVE_PROJECT_ID\");\n  }\n  const lock = await readLock(root);\n  const loaded = await loadBuildInputs(root, \"caveman.config.ts\");\n  const checked = await validLockIdentity(root, loaded.config.entry);\n  if (!checked || checked.build_sha256 !== lock.build_sha256) {\n    throw new Error(\"cave_stale_lock:registration\");\n  }\n  const response = await fetch(`${controlURL}/api/v1/projects/${encodeURIComponent(projectID)}/agent-builds`, {\n    method: \"POST\",\n    headers: {\n      authorization: `Bearer ${token}`,\n      \"content-type\": \"application/json\",\n    },\n    body: JSON.stringify({\n      agent_slug: lock.agent_id,\n      build_sha256: lock.build_sha256,\n      plan_sha256: lock.plan_sha256,\n      source_sha256: lock.source_sha256,\n      eval_suite_sha256: lock.eval_suite_sha256,\n      catalog_sha256: lock.catalog_sha256,\n      transform_registry_sha256: lock.runtime.transform_registry_sha256,\n      harness: lock.harness.id,\n      adapter_version: lock.harness.adapter_version,\n      upstream_version: lock.harness.upstream_version,","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/cli.ts#L457-L493","documentation":"`register` verifies that the on-disk build lock still matches the current build inputs before uploading it. It loads the config, runs validLockIdentity over the entry, and compares the resulting build_sha256 with the lock's. If the identity check fails (no valid lock identity) or the hashes differ, the lock is stale and registration is refused with this coded error.","triggerScenarios":"Calling `caveman register` after source, config, evals, or dependency versions changed since the last `npm run build`, so validLockIdentity returns null or a build_sha256 different from the lock's; or the lock file is missing/malformed.","commonSituations":"Editing agent source or caveman.config.ts after building and then registering without rebuilding; a teammate bumped a dependency that changes the transform registry hash; registering a CI artifact built from a different commit.","solutions":["Run `npm run build` (the caveman build command) to regenerate the lock.","Re-run `caveman register` after the fresh build.","If inputs should not have changed, `git status`/`git diff` to find and revert accidental edits made after the build.","Verify the lock file exists and was produced by the same commit you are registering."],"exampleFix":"// before\ncaveman register   # throws cave_stale_lock:registration\n// after\nnpm run build && caveman register","handlingStrategy":"retry","validationCode":"// after any source/config change, rebuild first\nawait run([\"npm\", \"run\", \"build\"]);\n// then register\nawait run([\"npx\", \"caveman\", \"register\"]);","typeGuard":null,"tryCatchPattern":"try {\n  await register();\n} catch (err) {\n  if (String(err?.message).startsWith(\"cave_stale_lock\")) {\n    await run([\"npm\", \"run\", \"build\"]); // relock\n    await register(); // retry once\n  } else throw err;\n}","preventionTips":["Always rebuild (npm run build) after editing source, evals, or config before registering.","Automate register behind the build target so ordering is guaranteed.","Avoid hand-editing generated lock files.","Pin dependency versions so hashes don't drift unexpectedly."],"tags":["cli","stale-lock","build"],"backgroundTag":"checksum-mismatch","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}