Hmbown/CodeWhale · error · ErrorEnvelope
provider stream error
Error message
provider stream error
What it means
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.
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.
Defensive patterns
Strategy: retry
Try / catch
match turn_result { Err(e) if is_provider_stream_error(&e) => retry_with_backoff_limited(turn, 3), other => other } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- provider stream error
- DS4 /v1/models could not be reached at
- Model stream ended with no answer or tool call.
- runtime event stream ended before turn.completed
- Runtime event stream ended inside a frame
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/df21b128addeca7d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/core/engine/turn_loop.rs:5226
usage_reported |= usage_has_reported_data(&u);
merge_stream_usage(&mut usage, u);
}
}
StreamEvent::MessageStop | StreamEvent::Ping => {}
StreamEvent::Error { error } => {
// #3014: providers surface mid-stream failures as a
// chunk-level `error` object (chat.rs converts the frame
// to this event and keeps parsing later frames as
// deltas). Historically this arm only warned and kept
// consuming, so every delta after the failure frame —
// including reasoning — still rendered while the real
// error vanished into the retry tail. A mid-stream error
// frame is terminal for this stream: surface it through
// the same typed envelope contract, record it as the
// turn's stream error, and stop consuming. Deltas that
// arrive after the failure frame are never forwarded.
let message = error
.get("message")
.and_then(Value::as_str)
.unwrap_or("provider stream error");
let envelope = ErrorEnvelope::classify(message.to_string(), true);
crate::logging::warn(format!("Provider stream error event: {message}"));
let _ = self.tx_event.send(Event::error(envelope)).await;
stream_error.get_or_insert(message.to_string());
break;
}
}
}
// A stream cut at the provider's output limit ends without the
// closing ContentBlockStop for whatever block was in flight. Those
// blocks' inputs still hold the mid-stream mirror's best-effort
// parse, which ignores `structure_synthesized` by design — left
// as-is, a truncated tool call reaches dispatch through
// `tool.input` and executes (#5986). Every block that never
// stopped goes through the same finalization gate a normal
// ContentBlockStop applies, and is announced with the sameView on GitHub (pinned to 433685b202)