{"record":{"id":"cf5dc9aeec3acefa","repo":"Hmbown/CodeWhale","slug":"sse-stream-request-failed-http-status-error-t","errorCode":null,"errorMessage":"SSE stream request failed: HTTP {status}: {error_text}","messagePattern":"SSE stream request failed: HTTP (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/client/chat.rs","lineNumber":1230,"sourceCode":"\n        let (response, stream_idle_timeout) = self.open_chat_stream_response(&url, &body).await?;\n\n        let status = response.status();\n        crate::client::record_provider_response(self.api_provider, status.as_u16());\n        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            // If DeepSeek rejected for missing reasoning_content despite the\n            // sanitizer, dump the offending indices so we can diagnose where\n            // they came from on the next failure.\n            if error_text.contains(\"reasoning_content\") {\n                log_thinking_mode_violations(&body);\n            }\n            anyhow::bail!(\"SSE stream request failed: HTTP {status}: {error_text}\");\n        }\n\n        let api_provider = self.api_provider;\n        let base_url = self.base_url.clone();\n\n        // Capture transport-shape headers before we consume `response` into\n        // `bytes_stream()`. They are surfaced in the decode-error log path so\n        // we can tell HTTP/2 RST_STREAM from chunked-encoding corruption from\n        // gzip-compressor failure when investigating #103.\n        let response_headers = format_stream_headers(response.headers());\n        let byte_stream = response.bytes_stream();\n        let configured_reasoning_stream_style = self.reasoning_stream_style.clone();\n\n        let stream = async_stream::stream! {\n            use futures_util::StreamExt;\n\n            // Emit a synthetic MessageStart\n            yield Ok(StreamEvent::MessageStart {","sourceCodeStart":1212,"sourceCodeEnd":1248,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/client/chat.rs#L1212-L1248","documentation":"The streaming (SSE) chat request was rejected with a non-2xx status before any body streamed. As a diagnostic special case, if the sanitized error text contains `reasoning_content`, the client logs `log_thinking_mode_violations` dumping the offending message indices — meaning the sanitizer failed to strip reasoning fields DeepSeek rejects for the selected model.","triggerScenarios":"Sending `reasoning_content`-bearing messages or thinking-mode parameters to a non-reasoning DeepSeek model; 401/429/500-style rejections on the streaming endpoint; invalid `stream` parameters.","commonSituations":"Switching a session from DeepSeek reasoner to DeepSeek chat while history contains reasoning blocks; enabling thinking mode on a model that does not support it; auth or quota issues surfacing on the stream endpoint.","solutions":["If the error text mentions `reasoning_content`, check the logged violation indices and strip reasoning blocks for the target model, or switch to the reasoner model","Match thinking-mode settings to a model that supports them","401/429: fix credentials or back off, per the embedded status","Verify the model ID and stream options against DeepSeek's current API"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_retryable_http_status_from_message(msg: &str) -> bool {\n    [408, 409, 429, 500, 502, 503, 504]\n        .iter()\n        .any(|s| msg.contains(&format!(\"HTTP {s}\")))\n}","tryCatchPattern":"match client.stream(request).await {\n    Err(e) if e.to_string().contains(\"reasoning_content\") => {\n        // Model/thinking-mode mismatch: strip reasoning blocks or switch model, then retry\n        retry_without_reasoning_content()\n    }\n    Err(e) if is_retryable_http_status_from_message(&e.to_string()) => backoff_retry().await,\n    Err(e) => Err(e),\n    Ok(stream) => Ok(stream),\n}","preventionTips":["Match thinking-mode parameters to models that support them; strip `reasoning_content` from history for chat models","Read the logged violation indices when this fires — they name the offending message positions","Verify stream-specific request options for the target model before enabling them"],"tags":["deepseek","sse","http","streaming","reasoning"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}