vxcontrol/pentagi · warning · RetryableError
failed to read response body: %w
Error message
failed to read response body: %w
What it means
The API responded with HTTP 200 but `io.ReadAll(resp.Body)` failed while reading the stream — connection reset mid-body, chunk encoding error, or context canceled during read. Wrapped as Retryable at backend/pkg/tools/searchers/perplexity.go:201 since re-issuing the request usually succeeds.
Source
Thrown at backend/pkg/tools/searchers/perplexity.go:201
if err != nil {
return "", Retryable(fmt.Errorf("failed to send request: %w", err), 0)
}
defer resp.Body.Close()
// Handling the response. handleErrorResponse keeps the per-status message; the
// retryable/fatal classification is decided here from the status code.
if resp.StatusCode != http.StatusOK {
baseErr := p.handleErrorResponse(resp.StatusCode)
if resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode >= 500 {
return "", Retryable(baseErr, 0)
}
return "", Fatal(baseErr)
}
// Reading the response body
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", Retryable(fmt.Errorf("failed to read response body: %w", err), 0)
}
// Deserializing the response
var response CompletionResponse
if err := json.Unmarshal(body, &response); err != nil {
return "", Fatal(fmt.Errorf("failed to unmarshal response: %w", err))
}
// Forming the result
result := p.formatResponse(ctx, &response, query)
return result, nil
}
// handleErrorResponse handles erroneous HTTP statuses
func (p *perplexity) handleErrorResponse(statusCode int) error {
switch statusCode {
case http.StatusBadRequest:
return errors.New("request is invalid")View on GitHub (pinned to ea665308ba)
Solutions
- Retry the request — the error is typed Retryable for the orchestrator's fallback/retry path
- Increase the HTTP client timeout (p.timeout()) so body reads are not cut off
- Check intermediate proxies/VPN for connection-reset behavior on long responses
- If persistent, capture the wrapped cause (unexpected EOF vs context deadline) to target the network hop that drops the stream
Example fix
// before client.Timeout = 5 * time.Second // body read truncated // after client.Timeout = 60 * time.Second
Defensive patterns
Strategy: retry
Validate before calling
// give body reads enough budget
client := &http.Client{Timeout: 60 * time.Second} // generous for large completions Try / catch
_, err := engine.Handle(ctx, req)
if err != nil {
if searchers.IsRetryable(err) && strings.Contains(err.Error(), "failed to read response body") {
// transient stream truncation: retry with backoff
}
} Prevention
- Increase client timeout so 200-OK body draining is not cut off by the deadline
- Check intermediate proxies/TLS-inspection appliances for dropping large responses
- Watch for unexpected EOF patterns in logs to identify the failing network hop
- Prefer engines with local fallbacks so one flaky path does not break search
When it happens
Trigger: `search` passes the status check (200 OK), then ReadAll aborts: server closed the connection before EOF, truncated chunked transfer, transient proxy error mid-stream, or ctx deadline hit while draining the body.
Common situations: Flaky load balancer/proxy between PentAGI and Perplexity dropping long responses; client timeout slightly too small so the deadline fires during body read; TLS interception appliance resetting large responses.
Related errors
- there are temporarily offline for maintenance. please try ag
- failed to send request: %w
- failed to do request: %w
- failed to do request: %v
- bearer scheme must be used
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/0842e6660087b0b9.
Report an issue: GitHub.