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
- Fix or delete `.caveman/provider.json` — the safest valid form is `{ "model": "provider/model-id" }`.
- Validate with `node -e 'JSON.parse(require("fs").readFileSync(".caveman/provider.json","utf8"))'`.
- 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
- Write the file with JSON.stringify, not editors that add comments or trailing commas.
- Validate the file in a prebuild step.
- Remember: absent file is fine; broken file is fatal.
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
- caveman build: dataResidency is not enforced yet; refusing t
- caveman build: requiredFixturePassRate must be in (0,1]
- caveman build: qualityRetention must be in (0,1]
- caveman build: config must use strict lock and required sand
- caveman build: set CAVE_MODEL when zero or multiple provider
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/64a2bf4f33f0a067.
Report an issue: GitHub.