vxcontrol/pentagi · error

failed to read response body: %w

Error message

failed to read response body: %w

What it means

After a 200 response, io.ReadAll(resp.Body) failed while draining the DuckDuckGo HTML body. Typical causes are the connection dropping mid-body or the client timeout firing during the read. The search aborts without retry and Handle converts it into a Fatal engine error.

Source

Thrown at backend/pkg/tools/searchers/duckduckgo.go:188

		}

		if resp.StatusCode != http.StatusOK {
			resp.Body.Close()
			if attempt == duckduckgoMaxRetries-1 {
				return "", fmt.Errorf("unexpected status code: %d", resp.StatusCode)
			}
			select {
			case <-ctx.Done():
				return "", ctx.Err()
			case <-time.After(time.Second):
			}
			continue
		}

		body, err := io.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			return "", fmt.Errorf("failed to read response body: %w", err)
		}

		response, err = d.parseHTMLResponse(body)
		if err != nil {
			return "", fmt.Errorf("failed to parse search response: %w", err)
		}

		break
	}

	if response == nil || len(response.Results) == 0 {
		return "No results found", nil
	}

	// Limit results to requested number
	if len(response.Results) > maxResults {
		response.Results = response.Results[:maxResults]
	}

View on GitHub (pinned to ea665308ba)

Solutions

  1. Retry the search — a transient mid-body reset usually succeeds on a second run.
  2. Increase duckduckgoTimeout if body transfer is routinely cut off on slow networks.
  3. Check proxy stability if traffic goes through an intermediary that drops long transfers.
  4. Consider an io.LimitedReader cap so oversized/bogus bodies fail fast instead of hitting timeout.
Defensive patterns

Strategy: retry

Validate before calling

// ensure generous client timeout so body reads are not cut off
if client.Timeout < 30*time.Second {
    client.Timeout = 30 * time.Second
}

Type guard

var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
    // timeout during body read; retry is appropriate
}

Try / catch

body, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
    if errors.Is(err, context.Canceled) {
        return "", err
    }
    return "", retryable(fmt.Errorf("failed to read response body: %w", err))
}

Prevention

When it happens

Trigger: Network interruption or reset while reading the response stream; duckduckgoTimeout elapsing during body transfer (client.Timeout covers body reads); server closing connection early; context cancellation.

Common situations: Slow/unstable links or flaky proxies where the 200 arrives but the body stalls; large anomaly/challenge pages from DuckDuckGo exceeding the timeout; VPN disconnections mid-request.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/e76e9b323f669556. Report an issue: GitHub.