JuliusBrussee/caveman · error · Error

caveman build: invalid .caveman/provider.json

Error message

caveman build: invalid .caveman/provider.json

What it means

Thrown by `localProviderModel` when reading `.caveman/provider.json` fails with any error other than ENOENT. A missing file is fine (returns undefined); a file that exists but cannot be parsed as JSON with an optional string `model` — permission denied, invalid JSON, a directory — makes the build fail with this message instead of ignoring local provider override config.

Source

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

  };
}

function evalDynamicKinds(evals: readonly EvalDefinition[]): ReadonlySet<ContextKind> {
  const kinds = new Set<ContextKind>();
  if (evals.some((fixture) => fixture.quality.some((grader) => grader.type === "tool_called"))) {
    kinds.add("history");
    kinds.add("tool_result");
  }
  return kinds;
}

function localProviderModel(root: string): string | undefined {
  try {
    const parsed = JSON.parse(readFileSync(resolve(root, ".caveman/provider.json"), "utf8")) as { model?: unknown };
    return typeof parsed.model === "string" ? parsed.model : undefined;
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code === "ENOENT") return undefined;
    throw new Error("caveman build: invalid .caveman/provider.json");
  }
}

function detectedModel(): string {
  const configured = [
    process.env.ANTHROPIC_API_KEY && "anthropic/claude-haiku-4-5",
    process.env.OPENAI_API_KEY && "openai/gpt-5.4-mini",
    (process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY) && "google/gemini-2.5-flash",
  ].filter((value): value is string => typeof value === "string");
  if (configured.length !== 1) {
    throw new Error("caveman build: set CAVE_MODEL when zero or multiple provider credentials exist");
  }
  return configured[0]!;
}

async function loadAgent(path: string): Promise<AgentDefinition> {
  return agentFromImported(await importFresh(path));
}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Fix or delete `.caveman/provider.json` — the safest valid form is `{ "model": "provider/model-id" }`.
  2. Validate with `node -e 'JSON.parse(require("fs").readFileSync(".caveman/provider.json","utf8"))'`.
  3. If you don't need a local override, remove the file entirely (missing is tolerated).

Example fix

// before: .caveman/provider.json
{ 'model': 'anthropic/claude-haiku-4-5', }  // single quotes + trailing comma

// after
{ "model": "anthropic/claude-haiku-4-5" }
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync } from "node:fs";
import { resolve } from "node:path";

function providerOverrideParses(root: string): boolean {
  try {
    const parsed = JSON.parse(readFileSync(resolve(root, ".caveman/provider.json"), "utf8"));
    return parsed == null || typeof parsed.model === "string" || parsed.model === undefined;
  } catch (error) {
    return (error as NodeJS.ErrnoException).code === "ENOENT";
  }
}

Type guard

function isProviderOverride(v: unknown): v is { model?: string } {
  return typeof v === "object" && v !== null && ((v as { model?: unknown }).model === undefined || typeof (v as { model?: unknown }).model === "string");
}

Try / catch

try {
  await build(args);
} catch (error) {
  if (error instanceof Error && error.message === "caveman build: invalid .caveman/provider.json") {
    // fix the JSON syntax or delete the file, then retry
  } else throw error;
}

Prevention

When it happens

Trigger: `.caveman/provider.json` exists but contains a syntax error (trailing comma, single quotes, BOM from a Windows editor), is a directory, or has unreadable permissions. Any non-ENOENT filesystem/parse error from `readFileSync`/`JSON.parse` lands here.

Common situations: Hand-editing the override file and breaking JSON; tools writing partial files on crash; a checked-in file with comments (JSONC) that JSON.parse rejects; permission changes after a chmod/chown.

Related errors


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