wavetermdev/waveterm · error
openai %s: failed to read error response: %v
Error message
openai %s: failed to read error response: %v
What it means
This error is returned by parseOpenAIHTTPError when the OpenAI API returns a non-2xx HTTP response but the error body itself cannot be read from the response stream (io.ReadAll fails). The HTTP status (e.g. '500 Internal Server Error') and the underlying read error are wrapped into one message. It indicates a transport-level problem rather than an API-reported error.
Source
Thrown at pkg/aiusechat/openai/openai-backend.go:584
// At this point we have a valid SSE stream, so setup SSE handling
// From here on, errors must be returned through the SSE stream
if cont == nil {
sse.SetupSSE()
}
// Use eventsource decoder for proper SSE parsing
decoder := eventsource.NewDecoder(resp.Body)
stopReason, rtnMessages := handleOpenAIStreamingResp(ctx, sse, decoder, cont, chatOpts)
return stopReason, rtnMessages, rateLimitInfo, nil
}
// parseOpenAIHTTPError parses OpenAI API HTTP error responses
func parseOpenAIHTTPError(resp *http.Response) error {
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("openai %s: failed to read error response: %v", resp.Status, err)
}
logutil.DevPrintf("openai full error: %s\n", body)
// Try to parse as OpenAI error format first
var errorResp openAIErrorResponse
if err := json.Unmarshal(body, &errorResp); err == nil && errorResp.Error.Message != "" {
return fmt.Errorf("openai %s: %s", resp.Status, errorResp.Error.Message)
}
// Try to parse as proxy error format
var proxyErr uctypes.ProxyErrorResponse
if err := json.Unmarshal(body, &proxyErr); err == nil && !proxyErr.Success && proxyErr.Error != "" {
return fmt.Errorf("openai %s: %s", resp.Status, proxyErr.Error)
}
return fmt.Errorf("openai %s: %s", resp.Status, utilfn.TruncateString(string(body), 120))
}View on GitHub (pinned to a4447c1563)
Solutions
- Check network/proxy stability between client and the OpenAI API endpoint; retry the request
- Verify no custom http.RoundTripper or middleware is consuming or closing resp.Body before error parsing
- Add retries with backoff for transient network failures
- Enable DevPrintf logging to capture the request flow and reproduce the read failure
Example fix
// before
err := client.Do(req)
if err != nil { return err }
// a middleware drains resp.Body for logging, so error parsing fails
// after
// in your RoundTripper, buffer the body instead of consuming it:
bodyBytes, _ := io.ReadAll(resp.Body)
resp.Body = io.NopCloser(bytes.NewReader(bodyBytes)) // body available again downstream Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
null
Try / catch
if strings.Contains(err.Error(), "failed to read error response") {
// transient body-read failure: retry with backoff
time.Sleep(backoff)
return doChatRequest(ctx, msgs)
} Prevention
- Avoid middleware/RoundTrippers that consume resp.Body without restoring it
- Use retry with exponential backoff for chat API calls
- Monitor network/proxy health between client and provider
When it happens
Trigger: The response body stream was already consumed or closed before parseOpenAIHTTPError ran; connection reset mid-read of the error body; a proxy/interceptor closed resp.Body prematurely; context cancellation aborting the body read.
Common situations: Flaky corporate proxies or VPNs killing the connection on error responses; timeouts while reading large error bodies; misconfigured HTTP middleware (logging/retry layers) that drains the body; mobile/unstable networks.
Related errors
- %s
- request failed: %w
- cannot call ${methodName}: no web endpoint
- call ${methodName} failed: ${resp.status} ${resp.statusText}
- Failed to fetch config: ${configResponse.statusText}
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/60dd4c97e8a6962a.
Report an issue: GitHub.