JuliusBrussee/caveman · error

cave_invalid_lock

cave_invalid_lock

Error message

cave_invalid_lock:${integrity.join(",")}

What it means

Raised by parseCaveBuildLock when the lock file is structurally valid but its integrity fields no longer match the current environment: embedded SHA-256 hashes (context_ir, eval_suite, transform_registry, external_provenance) or version stamps (runtime, adapter, upstream) differ from the computed current values. The joined suffix names which fields went stale.

Solutions

  1. Rebuild: run caveman build to regenerate the lock against the current context IR, eval suite, and runtime
  2. If dependencies changed intentionally (caveman version, adapter, upstream), refresh the lock rather than reusing the old one
  3. Do not hand-edit hash fields; they exist to force an honest rebuild
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/agent/src/build.ts:526 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/a3397d0036f44f59. Report an issue: GitHub.

Appendix: source

Thrown at packages/agent/src/build.ts:526

  }
  const lock = value as unknown as CaveBuildLock;
  if (lock.schema_version !== 2 || lock.context_ir_schema !== "1" ||
      !isRecord(lock.harness) || !exactKeys(lock.harness, ["id", "adapter_version", "upstream_version"]) ||
      !["pi", "claude", "vercel-ai-sdk", "eve", "mastra"].includes(lock.harness.id) ||
      !isRecord(lock.runtime) || !exactKeys(lock.runtime, ["caveman_version", "transform_registry_sha256", "external_provenance_sha256"]) ||
      !isRecord(lock.evidence) || !exactKeys(lock.evidence, [
        "status", "basis", "quality_retention_lcb95", "error_rate", "p95_latency_ms",
        "catalog_cost_usd_per_task", "completed_runs",
      ]) ||
      lock.evidence.status !== "locked" || lock.evidence.basis !== "inferred" ||
      !isRecord(lock.selected_plan) || !exactKeys(lock.selected_plan, [
        "schema_version", "plan_id", "model", "reasoning", "segment_routes",
        "budgets", "recovery", "fallbacks",
      ]) || !validPlanShape(lock.selected_plan)) {
    throw new Error("cave_invalid_lock:shape");
  }
  const integrity = lockIntegrityErrors(lock);
  if (integrity.length > 0) throw new Error(`cave_invalid_lock:${integrity.join(",")}`);
  return lock;
}

function validPlanShape(plan: Record<string, unknown>): boolean {
  if (plan.schema_version !== 1 || typeof plan.plan_id !== "string" || typeof plan.model !== "string" ||
      !["none", "minimal", "low", "medium", "high"].includes(String(plan.reasoning)) ||
      !isRecord(plan.budgets) || !exactKeys(plan.budgets, [
        "instructions", "tools", "memory", "history", "results_artifacts",
        "reasoning", "output", "retry_cascade_reserve",
      ]) ||
      Object.values(plan.budgets).some((value) => !Number.isSafeInteger(value) || Number(value) < 0) ||
      !isRecord(plan.recovery) || !exactKeys(plan.recovery, ["namespace", "tools"]) ||
      !isRecord(plan.fallbacks) || !exactKeys(plan.fallbacks, ["unknown", "transform_error", "not_smaller"]) ||
      !Array.isArray(plan.segment_routes)) {
    return false;
  }
  return plan.segment_routes.every((route) =>
    isRecord(route) &&

View on GitHub (pinned to 3ee70a1026)