{"record":{"id":"dcae21f662ee14dd","repo":"JuliusBrussee/caveman","slug":"cave-claude-provider-unsupported","errorCode":null,"errorMessage":"cave_claude_provider_unsupported","messagePattern":"cave_claude_provider_unsupported","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/claude-runtime.ts","lineNumber":471,"sourceCode":"  const target = name.toLowerCase();\n  const kept = (raw ?? \"\").split(/\\r\\n|\\n|\\r/).filter((line) => {\n    if (!line.trim()) return false;\n    const colon = line.indexOf(\":\");\n    return (colon < 0 ? line : line.slice(0, colon)).trim().toLowerCase() !== target;\n  });\n  kept.push(`${name}: ${value}`);\n  return kept.join(\"\\n\");\n}\n\nfunction resolveClaudeModel(definition: AgentDefinition, rootDir: string): string {\n  const configured = typeof definition.model === \"string\"\n    ? definition.model\n    : process.env.CAVE_MODEL ?? localModel(rootDir) ??\n      (process.env.ANTHROPIC_API_KEY ? \"anthropic/claude-haiku-4-5\" : undefined);\n  if (configured === undefined) throw new Error(\"cave_claude_model_required\");\n  const separator = configured.indexOf(\"/\");\n  if (separator < 1 || configured.slice(0, separator) !== \"anthropic\") {\n    throw new Error(\"cave_claude_provider_unsupported\");\n  }\n  return normalizeClaudeModel(configured.slice(separator + 1));\n}\n\nfunction localModel(rootDir: string): string | undefined {\n  try {\n    const parsed = JSON.parse(readFileSync(resolve(rootDir, \".caveman/provider.json\"), \"utf8\")) as {\n      model?: unknown;\n    };\n    return typeof parsed.model === \"string\" ? parsed.model : undefined;\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n    throw new Error(\"caveman agent: invalid .caveman/provider.json\");\n  }\n}\n\nfunction normalizeClaudeModel(model: string): string {\n  return model.startsWith(\"anthropic/\") ? model.slice(\"anthropic/\".length) : model;","sourceCodeStart":453,"sourceCodeEnd":489,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/claude-runtime.ts#L453-L489","documentation":"resolveClaudeModel() resolved a model string but its provider prefix is not \"anthropic\" (or there is no \"provider/model\" separator at position >= 1). The Claude harness only speaks the Anthropic provider, so models like \"openai/gpt-4o\" or malformed strings like \"/claude-haiku\" are rejected before the SDK call.","triggerScenarios":"definition.model / CAVE_MODEL / provider.json model set to a non-Anthropic route (\"openai/...\", \"google/...\", \"groq/...\"), a bare model with no slash (\"claude-haiku-4-5\"), or a leading slash (\"/claude-haiku-4-5\" makes separator index 0 < 1).","commonSituations":"Copying a model string from another harness's config (the framework supports pi/vercel-ai-sdk lanes that use openrouter-style ids); switching a project from an OpenAI provider to the Claude harness without rewriting the model id; typo like \"anthropic:\" instead of \"anthropic/\".","solutions":["Rewrite the model id with the anthropic prefix: \"anthropic/claude-haiku-4-5\".","If you actually want a non-Anthropic model, select the harness/adapter that supports that provider instead of the Claude one.","Add a config-time lint that model strings for the Claude lane match /^anthropic\\/.+/."],"exampleFix":"// before\nconst definition = { id: \"x\", model: \"openai/gpt-4o-mini\" };\n\n// after\nconst definition = { id: \"x\", model: \"anthropic/claude-haiku-4-5\" };","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isAnthropicModelRoute(model: string): boolean {\n  const sep = model.indexOf(\"/\");\n  return sep >= 1 && model.slice(0, sep) === \"anthropic\";\n}","tryCatchPattern":null,"preventionTips":["Use provider-prefixed ids (\"anthropic/<model>\") everywhere; bare ids are rejected on the Claude lane.","Add a config lint asserting /^anthropic\\/.+/ for every model routed to the Claude harness.","When migrating configs between harnesses, remember model vocabularies differ — rewrite model ids, don't copy them."],"tags":["configuration","model-selection","provider-mismatch"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}