{"record":{"id":"df21b128addeca7d","repo":"Hmbown/CodeWhale","slug":"provider-stream-error","errorCode":null,"errorMessage":"provider stream error","messagePattern":"provider stream error","errorType":"console","errorClass":"ErrorEnvelope","httpStatus":null,"severity":"error","filePath":"crates/tui/src/core/engine/turn_loop.rs","lineNumber":5226,"sourceCode":"                        usage_reported |= usage_has_reported_data(&u);\n                        merge_stream_usage(&mut usage, u);\n                    }\n                }\n                StreamEvent::MessageStop | StreamEvent::Ping => {}\n                StreamEvent::Error { error } => {\n                    // #3014: providers surface mid-stream failures as a\n                    // chunk-level `error` object (chat.rs converts the frame\n                    // to this event and keeps parsing later frames as\n                    // deltas). Historically this arm only warned and kept\n                    // consuming, so every delta after the failure frame —\n                    // including reasoning — still rendered while the real\n                    // error vanished into the retry tail. A mid-stream error\n                    // frame is terminal for this stream: surface it through\n                    // the same typed envelope contract, record it as the\n                    // turn's stream error, and stop consuming. Deltas that\n                    // arrive after the failure frame are never forwarded.\n                    let message = error\n                        .get(\"message\")\n                        .and_then(Value::as_str)\n                        .unwrap_or(\"provider stream error\");\n                    let envelope = ErrorEnvelope::classify(message.to_string(), true);\n                    crate::logging::warn(format!(\"Provider stream error event: {message}\"));\n                    let _ = self.tx_event.send(Event::error(envelope)).await;\n                    stream_error.get_or_insert(message.to_string());\n                    break;\n                }\n            }\n        }\n        // A stream cut at the provider's output limit ends without the\n        // closing ContentBlockStop for whatever block was in flight. Those\n        // blocks' inputs still hold the mid-stream mirror's best-effort\n        // parse, which ignores `structure_synthesized` by design — left\n        // as-is, a truncated tool call reaches dispatch through\n        // `tool.input` and executes (#5986). Every block that never\n        // stopped goes through the same finalization gate a normal\n        // ContentBlockStop applies, and is announced with the same","sourceCodeStart":5208,"sourceCodeEnd":5244,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/core/engine/turn_loop.rs#L5208-L5244","documentation":"When a mid-stream error frame arrives from the provider (an error event inside the stream payload), the engine surfaces it through the typed ErrorEnvelope contract, logs it, records it as the turn's stream error, and stops consuming. The message text is taken from the error frame's \"message\" field, defaulting to \"provider stream error\" when absent. Deltas after the failure frame are never forwarded because the stream is terminal.","triggerScenarios":"Provider sends an error event within an in-progress response stream (error JSON frame with/without a message field) at turn_loop.rs ~5226; the engine classifies it via ErrorEnvelope::classify and terminates consumption.","commonSituations":"Provider-side outages or overload mid-generation; invalid request rejected only after streaming began; rate limiting or auth token expiring mid-stream; provider emitting malformed error frames without a message.","solutions":["Inspect the logged 'Provider stream error event: ...' warning for the provider's actual message to identify the cause.","Retry the turn — mid-stream provider failures are frequently transient (overload, network blip).","Check provider status page / API key validity and rate limits if it recurs.","If the provider consistently errors mid-stream, reduce request complexity or update the provider adapter."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match turn_result { Err(e) if is_provider_stream_error(&e) => retry_with_backoff_limited(turn, 3), other => other }","preventionTips":["Validate API keys and request payloads before starting streams so errors surface pre-stream.","Use a provider with healthy status and implement bounded retries for mid-stream failures.","Watch the logged provider message to catch systematic request problems early."],"tags":["streaming","provider","network","tui"],"backgroundTag":"upstream-api-error","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}