JuliusBrussee/caveman · error · Error
cave_claude_reasoning_capability_unknown:${model}
Error message
cave_claude_reasoning_capability_unknown:${model} What it means
claudeThinkingCapability() classifies models into "manual", "adaptive", or "unknown" by regex. Reasoning is enabled (not "off") but the resolved model matches neither regex, so the framework does not know how to configure thinking for it and fails closed rather than guessing a thinking mode that might error or silently no-op upstream. The model id is embedded in the message.
Source
Thrown at packages/agent/src/claude-runtime.ts:518
reasoning: AgentDefinition["reasoning"],
outputMaxTokens: number | undefined,
): Pick<ClaudeSDKOptions, "thinking" | "effort"> {
if (reasoning === "off") return { thinking: { type: "disabled" } };
const capability = claudeThinkingCapability(model);
if (capability === "adaptive") {
return {
thinking: { type: "adaptive" },
effort: claudeEffort(reasoning),
};
}
if (capability === "manual") {
const budgetTokens = reasoning === "high" ? 8_192 : reasoning === "medium" ? 4_096 : 1_024;
if (outputMaxTokens !== undefined && outputMaxTokens <= budgetTokens) {
throw new Error("cave_claude_output_budget_too_small_for_reasoning");
}
return { thinking: { type: "enabled", budgetTokens } };
}
throw new Error(`cave_claude_reasoning_capability_unknown:${model}`);
}
function claudeThinkingCapability(model: string): "adaptive" | "manual" | "unknown" {
if (/^claude-(?:haiku-4-5|sonnet-4-5|opus-4-(?:1|5))(?:-\d{8})?$/.test(model)) {
return "manual";
}
if (/^claude-(?:sonnet|opus)-4-[678](?:-\d{8})?$/.test(model) ||
/^claude-(?:fable|mythos|sonnet|opus)-5(?:-\d+)?$/.test(model)) {
return "adaptive";
}
return "unknown";
}
// Accepts ANY result subtype: error subtypes (error_max_turns, …) carry the
// same provider `usage` a success does, so the receipt can be built from a
// failed run too.
type ClaudeCredentialRegime = "metered" | "subscription" | "unknown";
View on GitHub (pinned to 27d5a3981a)
Solutions
- Use a known model family: manual (claude-haiku-4-5, claude-sonnet-4-5, claude-opus-4-1, claude-opus-4-5) or adaptive (claude-sonnet/opus-4-6/4-7/4-8, claude-fable/mythos/sonnet/opus-5).
- Check the embedded model id in the message for typos against those exact patterns (note the optional 8-digit date suffix).
- If the model is genuinely new, upgrade the caveman agent package so claudeThinkingCapability knows it, or set reasoning: "off" until then.
Example fix
// before
await run({ prompt, model: "anthropic/claude-3-5-sonnet", reasoning: "medium" });
// → cave_claude_reasoning_capability_unknown:claude-3-5-sonnet
// after
await run({ prompt, model: "anthropic/claude-sonnet-4-5", reasoning: "medium" }); Defensive patterns
Strategy: validation
Validate before calling
const KNOWN_THINKING_MODEL =
/^claude-(?:haiku-4-5|sonnet-4-5|opus-4-(?:1|5))(?:-\d{8})?$/;
const KNOWN_ADAPTIVE_MODEL =
/^claude-(?:sonnet|opus)-4-[678](?:-\d{8})?$/ ||
/^claude-(?:fable|mythos|sonnet|opus)-5(?:-\d+)?$/;
function reasoningSupported(model: string): boolean {
return KNOWN_THINKING_MODEL.test(model) || KNOWN_ADAPTIVE_MODEL.test(model);
} Type guard
function supportsReasoning(model: string): boolean {
return /^claude-(?:haiku-4-5|sonnet-4-5|opus-4-(?:1|5))(?:-\d{8})?$/.test(model)
|| /^claude-(?:sonnet|opus)-4-[678](?:-\d{8})?$/.test(model)
|| /^claude-(?:fable|mythos|sonnet|opus)-5(?:-\d+)?$/.test(model);
} Try / catch
try {
await run({ ...options, reasoning: "medium" });
} catch (error) {
if (error instanceof Error && error.message.startsWith("cave_claude_reasoning_capability_unknown:")) {
const model = error.message.split(":")[1];
return run({ ...options, reasoning: "off" }); // degrade to no thinking
}
throw error;
} Prevention
- Read the model id out of the error message — it tells you exactly which string failed classification.
- Before enabling reasoning on a new model, upgrade the caveman agent package so its capability regexes cover the release.
- Prefer exact dated snapshots (claude-sonnet-4-5-20250929) or canonical names that match the documented patterns.
When it happens
Trigger: reasoning != "off" with any model outside the known families: e.g. "claude-3-5-sonnet", "claude-opus-4", a future release like "claude-sonnet-6-20260101" before the regexes are updated, or a custom/renamed deployment id. Alias forms that don't match the exact patterns also fall through.
Common situations: Anthropic ships a new model generation and the framework pin predates it; user config uses an internal alias or dated snapshot not covered by the (?:-\d{8})? patterns; typos like "claude-haiku-45" (missing dash) classify as unknown.
Related errors
- cave_budget_denomination_unavailable
- cave_claude_model_required
- cave_claude_output_budget_too_small_for_reasoning
- cave_harness_upstream_version_mismatch
- cave_claude_header_invalid
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/da303e2acf305ff9.
Report an issue: GitHub.