{"record":{"id":"8156c77f24aaddf8","repo":"Hmbown/CodeWhale","slug":"fim-response-missing-choices-0-text","errorCode":null,"errorMessage":"FIM response missing choices[0].text","messagePattern":"FIM response missing choices\\[0\\]\\.text","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/client.rs","lineNumber":3642,"sourceCode":"        if !status.is_success() {\n            let raw_error_text = bounded_error_text(response, ERROR_BODY_MAX_BYTES).await;\n            let error_text = sanitize_http_error_body(\n                Some(self.api_provider.display_name()),\n                status.as_u16(),\n                &raw_error_text,\n            );\n            anyhow::bail!(\"FIM API error: HTTP {status}: {error_text}\");\n        }\n        let response_text = response\n            .text()\n            .await\n            .context(\"Failed to read FIM API response body\")?;\n        let value: serde_json::Value =\n            serde_json::from_str(&response_text).context(\"Failed to parse FIM API response\")?;\n        let text = value\n            .pointer(\"/choices/0/text\")\n            .and_then(serde_json::Value::as_str)\n            .ok_or_else(|| anyhow::anyhow!(\"FIM response missing choices[0].text\"))?;\n        Ok(text.to_string())\n    }\n}\n\nmod anthropic;\nmod chat;\npub(crate) mod cloud_code;\nmod deepseek_effort;\n#[cfg(test)]\nmod ds4_tests;\nmod prepared;\nmod provider_native_search;\nmod responses;\nmod stream_entry;\n\nfn extract_sse_data_value(line: &str) -> Option<&str> {\n    line.strip_prefix(\"data:\")\n        .map(|value| value.strip_prefix(' ').unwrap_or(value))","sourceCodeStart":3624,"sourceCodeEnd":3660,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/client.rs#L3624-L3660","documentation":"After a 2xx from `{base_url}/beta/completions`, `fim_completion` extracts the completion with the JSON pointer `/choices/0/text` and requires a string. This error means the endpoint returned success but a body without that field — a chat-completions-shaped reply (`choices[0].message.content`), an envelope-wrapped response, or an empty `choices` array. It is the shape-mismatch counterpart of the HTTP-status error above.","triggerScenarios":"A gateway that answers `/beta/completions` with 200 but routes the request to chat-completions internally (returning `message.content` instead of `text`); providers whose FIM reply nests the completion elsewhere; 200 responses containing a JSON error object.","commonSituations":"LiteLLM/proxy layers normalizing everything to chat shape; custom `base_url`s where a catch-all handler returns 200 JSON for unknown paths; server versions that renamed the field.","solutions":["Inspect the raw body with curl (same request as the FIM call) and compare: FIM needs `choices[0].text`, chat gives `choices[0].message.content`.","Route FIM to a true DeepSeek-compatible FIM endpoint rather than a chat-normalizing proxy.","If you control the gateway, map `/beta/completions` responses to include `choices[].text`."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn has_fim_text(v: &serde_json::Value) -> bool {\n    v.pointer(\"/choices/0/text\").is_some_and(serde_json::Value::is_string)\n}","tryCatchPattern":"let text = value.pointer(\"/choices/0/text\").and_then(Value::as_str)\n    .ok_or_else(|| anyhow::anyhow!(\n        \"FIM response missing choices[0].text (got keys: {:?}) — endpoint is not FIM-shaped\",\n        value.as_object().map(|o| o.keys().collect::<Vec<_>>())))?;","preventionTips":["Prefer a gateway route that forwards DeepSeek FIM responses verbatim rather than normalizing to chat shape.","Probe the FIM endpoint once at startup and validate the response shape, not just the status code.","When shapes mismatch persistently, disable FIM rather than erroring per keystroke."],"tags":["fim","response-parsing","api","deepseek","proxy"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}