fish2018/pansou · error
read response body failed
Error message
read response body failed (page %d, type %s): %w
What it means
io.ReadAll on the API response body failed, so the raw JSON could not be obtained. The wrapped error (with page/disk type) is sent to errChan. Typically this is a connection dropped mid-body or a truncated/chunked response.
Solutions
- Retry the request — this error is usually transient network interruption
- Disable HTTP keep-alive connection reuse or set a fresh transport to avoid stale-connection resets
- Check proxy/VPN stability if responses are consistently truncated
- Increase transport timeouts (ResponseHeaderTimeout, idle conn settings) if applicable
Example fix
// before
respBody, err := io.ReadAll(resp.Body)
if err != nil {
errChan <- fmt.Errorf("read response body failed (page %d, type %s): %w", pageNum, diskType, err)
return
}
// after
respBody, err := io.ReadAll(io.LimitReader(resp.Body, 10<<20))
if err != nil {
errChan <- fmt.Errorf("read response body failed (page %d, type %s): %w", pageNum, diskType, err)
return // caller should retry this page on transient read errors
} Defensive patterns
Strategy: retry
Validate before calling
respBody, err := io.ReadAll(io.LimitReader(resp.Body, maxBody))
if err != nil {
return fmt.Errorf("body read failed (transient?): %w", err)
} Try / catch
if err != nil {
if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, context.DeadlineExceeded) {
// retry the page once
}
} Prevention
- Retry page fetches on read errors — they are usually transient
- Use io.LimitReader to bound body size
- Check proxy/VPN stability if truncation is frequent
- Disable stale keep-alive reuse or set MaxIdleConnsPerHost appropriately
When it happens
Trigger: The connection is reset or times out while reading resp.Body (server closes early, proxy interference, network interruption during transfer).
Common situations: Unstable network or mobile connection; server/proxy kills long responses; keep-alive connection reused after going stale; response is huge and the read hits a context/transport deadline.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/b0fb6ac17b8ae82d.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/sousou/sousou.go:434
errChan <- fmt.Errorf("request failed (page %d, type %s): %w", pageNum, diskType, err)
return
}
defer resp.Body.Close()
debugLog("收到响应 (page %d, type %s), 状态码: %d", pageNum, diskType, resp.StatusCode)
// 检查状态码
if resp.StatusCode != 200 {
debugLog("HTTP错误 (page %d, type %s): %d", pageNum, diskType, resp.StatusCode)
errChan <- fmt.Errorf("HTTP error (page %d, type %s): %d", pageNum, diskType, resp.StatusCode)
return
}
// 读取响应体
respBody, err := io.ReadAll(resp.Body)
if err != nil {
debugLog("读取响应失败 (page %d, type %s): %v", pageNum, diskType, err)
errChan <- fmt.Errorf("read response body failed (page %d, type %s): %w", pageNum, diskType, err)
return
}
debugLog("响应内容 (page %d, type %s, 前500字符): %s", pageNum, diskType, string(respBody[:min(500, len(respBody))]))
// 解析响应
var apiResp SousouResponse
if err := json.Unmarshal(respBody, &apiResp); err != nil {
debugLog("JSON解析失败 (page %d, type %s): %v", pageNum, diskType, err)
errChan <- fmt.Errorf("decode response failed (page %d, type %s): %w", pageNum, diskType, err)
return
}
// 检查响应状态
if apiResp.Code != 200 {
debugLog("API返回错误 (page %d, type %s): code=%d, msg=%s", pageNum, diskType, apiResp.Code, apiResp.Msg)
errChan <- fmt.Errorf("API returned error (page %d, type %s): %s", pageNum, diskType, apiResp.Msg)
returnView on GitHub (pinned to beaa561337)