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

  1. Approve the required evals, then run `npm run build` to generate the lock.
  2. Re-run the verify command after the build succeeds.
  3. If the lock should exist, check .gitignore — commit the lock file if your team intends it to be shared.
  4. 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

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


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)