fix(tui): classify stream decode failures as network errors

Classify stream/body decode failures such as the #2847 report as recoverable network interruptions and add focused taxonomy coverage.\n\nVerification:\n- cargo test -p codewhale-tui error_taxonomy::tests --locked\n- git diff --check\n- cmp -s CHANGELOG.md crates/tui/CHANGELOG.md\n- ./scripts/release/check-versions.sh\n- ./scripts/release/check-ohos-deps.sh
This commit is contained in:
Hunter Bown
2026-06-06 01:54:36 -07:00
committed by GitHub
parent 23a188e8fd
commit 35cd09a9f7
3 changed files with 30 additions and 0 deletions
+5
View File
@@ -310,6 +310,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Stream/body decode failures such as `Stream read error: error decoding
response body` are now classified as recoverable network interruptions
instead of generic internal errors, keeping the transcript and triage metadata
aligned with the existing stream retry path (#2847). Thanks
@qamranmushtaq-collab for the Windows/npx DeepSeek report.
- The TUI footer, `/status`, `/mcp` manager, and command-palette MCP entries
now count trusted workspace-local `.codewhale/mcp.json` servers together with
the global MCP config, matching `codewhale mcp list` for merged global +
+5
View File
@@ -310,6 +310,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Stream/body decode failures such as `Stream read error: error decoding
response body` are now classified as recoverable network interruptions
instead of generic internal errors, keeping the transcript and triage metadata
aligned with the existing stream retry path (#2847). Thanks
@qamranmushtaq-collab for the Windows/npx DeepSeek report.
- The TUI footer, `/status`, `/mcp` manager, and command-palette MCP entries
now count trusted workspace-local `.codewhale/mcp.json` servers together with
the global MCP config, matching `codewhale mcp list` for merged global +
+20
View File
@@ -342,6 +342,10 @@ pub fn classify_error_message(message: &str) -> ErrorCategory {
if lower.contains("network")
|| lower.contains("connection")
|| lower.contains("dns")
|| lower.contains("stream read error")
|| lower.contains("error decoding response body")
|| lower.contains("chunk decode error")
|| lower.contains("body decode")
|| lower.contains("temporarily unavailable")
|| lower.contains(" 502 ")
|| lower.contains(" 503 ")
@@ -548,6 +552,22 @@ mod tests {
);
}
#[test]
fn network_catches_stream_body_decode_failures() {
for msg in [
"Warn Stream read error: error decoding response body",
"Stream read error: error decoding response body",
"chunk decode error",
"provider body decode failed mid-stream",
] {
assert_eq!(
classify(msg),
ErrorCategory::Network,
"expected Network for `{msg}`",
);
}
}
#[test]
fn authentication_beats_authorization_when_api_key_phrasing_is_used() {
// "api key" landing on Authentication (not Authorization) keeps