JuliusBrussee/caveman · error
cave_build_lock_missing
cave_build_lock_missing
Error message
cave_build_lock_missing: approve required evals, then run npm run build
What it means
The verify/lock-check command loads build inputs and then attempts readLock(root). If the lock file does not exist (ENOENT), the error is replaced with this actionable message: evaluation approval must happen first and then a build run creates the lock. Without a lock there is nothing to verify.
Solutions
- Approve the required evals, then run `npm run build` to generate the lock.
- Re-run the verify command after the build succeeds.
- If the lock should exist, check .gitignore — commit the lock file if your team intends it to be shared.
- Confirm you are in the correct project root (readLock reads process cwd/root).
Example fix
// before caveman verify # cave_build_lock_missing // after npm run build caveman verify
Defensive patterns
Strategy: validation
Validate before calling
import { existsSync } from "node:fs";
if (!existsSync("cave-build-lock.json")) {
console.error("No build lock; run: npm run build");
process.exit(1);
} Try / catch
try {
await verify();
} catch (err) {
if (String(err?.message).startsWith("cave_build_lock_missing")) {
await run(["npm", "run", "build"]); // create the lock, then re-verify
await verify();
} else throw err;
} Prevention
- Run npm run build as part of initial repo setup after cloning.
- Decide whether the lock is committed; if gitignored, document the build-first step in the README.
- Add the build step to CI before any verify/register command.
- Never manually delete lock files without rebuilding.
When it happens
Trigger: Running the lock-verification command (cli.ts:939) in a project root where no cave build lock file exists yet — i.e. `npm run build` was never run after approving required evals.
Common situations: Fresh clone of a repo where the lock file is gitignored; new contributor who skipped the build step; switching branches to one without a lock; cleaning the working tree and deleting the lock.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- caveman-cloud MCP changed after setup; refusing destructive…
- caveman-cloud MCP changed during interrupted setup…
- caveman-cloud MCP changed during interrupted removal…
- caveman-cloud MCP postflight mismatch
- caveman-cloud MCP registration failed exact postflight
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/63d58198560d114c.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/cli.ts:939
function configuredModelCandidates(baseline: string): string[] {
const models = new Set<string>([baseline]);
if (process.env.ANTHROPIC_API_KEY) models.add("anthropic/claude-haiku-4-5");
if (process.env.OPENAI_API_KEY) models.add("openai/gpt-5.4-mini");
if (process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY) models.add("google/gemini-2.5-flash");
return [...models].sort();
}
async function check(args: string[]): Promise<void> {
const root = process.cwd();
const configPath = args[0] ?? "caveman.config.ts";
const loaded = await loadBuildInputs(root, configPath);
let lock: CaveBuildLock;
try {
lock = await readLock(root);
} catch (error) {
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
throw new Error("cave_build_lock_missing: approve required evals, then run npm run build");
}
throw error;
}
const transformRegistrySha256 = await transformRegistrySHA256();
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,
catalogSha256: CATALOG_SHA256,
});View on GitHub (pinned to 3ee70a1026)