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

  1. Check network/proxy stability between client and the OpenAI API endpoint; retry the request
  2. Verify no custom http.RoundTripper or middleware is consuming or closing resp.Body before error parsing
  3. Add retries with backoff for transient network failures
  4. 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

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


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/60dd4c97e8a6962a. Report an issue: GitHub.