JuliusBrussee/caveman · error
cave_claude_model_required
cave_claude_model_required
Error message
cave_claude_model_required
What it means
resolveClaudeModel must produce a model string; it consults definition.model, the CAVE_MODEL env var, the project-local model config, and finally defaults to anthropic/claude-haiku-4-5 only when ANTHROPIC_API_KEY is set. If every source is empty, it throws this error.
Solutions
- Set definition.model to an anthropic-prefixed model, e.g. "anthropic/claude-haiku-4-5"
- Export CAVE_MODEL=anthropic/claude-sonnet-4-5 (or add the model to the local config in rootDir)
- Set ANTHROPIC_API_KEY so the haiku-4-5 default applies
Example fix
// before
await runClaudeAgent({ definition, input }); // no model anywhere
// after
await runClaudeAgent({ definition: { ...definition, model: "anthropic/claude-haiku-4-5" }, input }); Defensive patterns
Strategy: validation
Validate before calling
if (!definition.model && !process.env.CAVE_MODEL && !process.env.ANTHROPIC_API_KEY) throw new Error("Set definition.model, CAVE_MODEL, or ANTHROPIC_API_KEY before running"); Try / catch
try { await runClaudeAgent(opts); } catch (e) { if (e.message === "cave_claude_model_required") { opts.definition = { ...opts.definition, model: "anthropic/claude-haiku-4-5" }; return runClaudeAgent(opts); } throw e; } Prevention
- Always set a model on agent definitions targeting Claude
- Load .env before invoking the runtime
- In CI, export CAVE_MODEL explicitly
When it happens
Trigger: Calling runClaudeAgent with a definition lacking a model, no CAVE_MODEL set, no local model config file, and no ANTHROPIC_API_KEY in the environment.
Common situations: Fresh checkout without .env loaded; CI environment missing CAVE_MODEL/ANTHROPIC_API_KEY; running outside the project root so the local model config file isn't found.
Understand the failure class
Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.
Related errors
- caveman-code: no supported provider credential found; set…
- invalid CAVEMAN_LISTEN
- invalid listener
- objectstore: S3_ENDPOINT is required in production
- register requires CAVE_CONTROL_URL, CAVE_TOKEN, and…
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/88cce697c87ea53c.
Report an issue: GitHub.
Appendix: source
Thrown at packages/agent/src/claude-runtime.ts:468
if (/[:\r\n]/.test(name) || /[\r\n]/.test(value)) {
throw new Error("cave_claude_header_invalid");
}
const target = name.toLowerCase();
const kept = (raw ?? "").split(/\r\n|\n|\r/).filter((line) => {
if (!line.trim()) return false;
const colon = line.indexOf(":");
return (colon < 0 ? line : line.slice(0, colon)).trim().toLowerCase() !== target;
});
kept.push(`${name}: ${value}`);
return kept.join("\n");
}
function resolveClaudeModel(definition: AgentDefinition, rootDir: string): string {
const configured = typeof definition.model === "string"
? definition.model
: process.env.CAVE_MODEL ?? localModel(rootDir) ??
(process.env.ANTHROPIC_API_KEY ? "anthropic/claude-haiku-4-5" : undefined);
if (configured === undefined) throw new Error("cave_claude_model_required");
const separator = configured.indexOf("/");
if (separator < 1 || configured.slice(0, separator) !== "anthropic") {
throw new Error("cave_claude_provider_unsupported");
}
return normalizeClaudeModel(configured.slice(separator + 1));
}
function localModel(rootDir: string): string | undefined {
try {
const parsed = JSON.parse(readFileSync(resolve(rootDir, ".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 agent: invalid .caveman/provider.json");
}
}View on GitHub (pinned to 3ee70a1026)