{"record":{"id":"40510f7672e6c302","repo":"sigoden/aichat","slug":"invalid-response-data-data-40510f","errorCode":null,"errorMessage":"Invalid response data: {data}","messagePattern":"Invalid response data: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/client/claude.rs","lineNumber":342,"sourceCode":"                        item[\"id\"].as_str(),\n                    ) {\n                        tool_calls.push(ToolCall::new(\n                            name.to_string(),\n                            input.clone(),\n                            Some(id.to_string()),\n                        ));\n                    }\n                }\n                _ => {}\n            }\n        }\n    }\n    if let Some(reasoning) = reasoning {\n        text = format!(\"<think>\\n{reasoning}\\n</think>\\n\\n{text}\")\n    }\n\n    if text.is_empty() && tool_calls.is_empty() {\n        bail!(\"Invalid response data: {data}\");\n    }\n\n    let output = ChatCompletionsOutput {\n        text: text.to_string(),\n        tool_calls,\n        id: data[\"id\"].as_str().map(|v| v.to_string()),\n        input_tokens: data[\"usage\"][\"input_tokens\"].as_u64(),\n        output_tokens: data[\"usage\"][\"output_tokens\"].as_u64(),\n    };\n    Ok(output)\n}\n","sourceCodeStart":324,"sourceCodeEnd":354,"githubUrl":"https://github.com/sigoden/aichat/blob/82976d349ad97ac9aae0655ad631dace5e2a6385/src/client/claude.rs#L324-L354","documentation":"In claude_extract_chat_completions, a successful Anthropic Messages response parsed to neither text content nor tool calls (reasoning blocks alone don't count). The library considers this an unusable empty completion and bails with the raw response JSON embedded in the message.","triggerScenarios":"claude_chat_completions gets a 2xx response where the content array contains no text/tool_use blocks — e.g. only thinking blocks, an empty content array, or refusal/stop_reason-only responses the extractor doesn't convert.","commonSituations":"max_tokens exhausted by thinking tokens (extended thinking models) leaving no text output, content filtered by safety, or Anthropic response schema changes.","solutions":["Inspect {data} for the actual content array and stop_reason","Increase max_tokens — thinking tokens consume the budget and can leave zero text tokens","Check stop_reason (e.g. refusal, max_tokens) in the payload","If using extended-thinking models, ensure the library version extracts text blocks correctly / update the library","Capture thinking blocks separately if reasoning-only output is expected"],"exampleFix":"// before\n.with_max_tokens(512)  // consumed entirely by thinking -> empty text\n// after\n.with_max_tokens(4096)  // headroom for thinking + text","handlingStrategy":"try-catch","validationCode":"// Give thinking models headroom\nif max_tokens <= thinking_budget { return Err(\"max_tokens must exceed thinking budget\".into()); }","typeGuard":null,"tryCatchPattern":"match client.chat_completions(req).await {\n    Err(e) if e.to_string().starts_with(\"Invalid response data\") => {\n        // inspect {data} for content blocks / stop_reason\n        Err(anyhow!(\"claude empty completion: {e}\"))\n    }\n    r => r,\n}","preventionTips":["Increase max_tokens when using extended-thinking models","Inspect stop_reason (max_tokens, refusal) on empty outputs","Upgrade the library when Anthropic changes response shapes","Capture thinking blocks if reasoning-only responses are expected"],"tags":["claude","anthropic","empty-response","api-response","parsing"],"backgroundTag":"empty-api-response","analyzedSha":"82976d349ad97ac9aae0655ad631dace5e2a6385","analyzedAt":"2026-09-09T18:33:06.139Z","contentChangedAt":"2026-09-09T18:33:06.139Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}