fish2018/pansou · error
[ ] 读取响应失败
Error message
[%s] 读取响应失败: %w
What it means
ikantv plugin's doSearch throws this when io.ReadAll(resp.Body) fails after a 200 response. The response body could not be read to completion — the connection dropped mid-transfer or a transport-level read failed.
Solutions
- Retry the request; a mid-body drop is typically transient.
- Review the HTTP client's Transport timeouts (ResponseHeaderTimeout vs overall context) to ensure the body has time to transfer.
- Disable connection reuse if stale keep-alive connections repeatedly reset.
- Treat repeated occurrences as an upstream/network stability problem and log the wrapped io error.
Example fix
// before
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err)
}
// after
body, err := io.ReadAll(io.LimitReader(resp.Body, maxBodySize))
if err != nil {
return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err)
}
if len(body) == 0 {
return nil, fmt.Errorf("[%s] 响应体为空", p.Name())
} Defensive patterns
Strategy: retry
Try / catch
results, err := p.doSearch(ctx, keyword)
if err != nil && strings.Contains(err.Error(), "读取响应失败") {
// transient body read failure: retry once after a short backoff
time.Sleep(500 * time.Millisecond)
results, err = p.doSearch(ctx, keyword)
} Prevention
- Retry mid-body read failures — they are usually transient
- Use io.LimitReader to cap transfer size on unstable links
- Match Transport read timeouts to expected body sizes
- Investigate repeated occurrences as upstream/CDN instability
When it happens
Trigger: io.ReadAll(resp.Body) returns err on a 200 response: unexpected EOF from an abruptly closed connection, reset by peer, or read deadline hit while streaming the body.
Common situations: Upstream or CDN closes keep-alive connections prematurely; large responses interrupted by an unstable network; client Transport ReadTimeout shorter than the body transfer.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/246535152f83b132.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/ikantv/ikantv.go:95
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
req.Header.Set("Accept", "application/json, text/plain, */*")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Referer", defaultReferer)
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] 请求返回状态码: %d", p.Name(), resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err)
}
var apiResp apiResponse
if err := json.Unmarshal(body, &apiResp); err != nil {
return nil, fmt.Errorf("[%s] JSON解析失败: %w", p.Name(), err)
}
if apiResp.Code != 0 {
return nil, fmt.Errorf("[%s] API错误: %s", p.Name(), apiResp.Message)
}
results := convertResults(apiResp.Data)
return plugin.FilterResultsByKeyword(results, keyword), nil
}
func convertResults(items []apiItem) []model.SearchResult {
results := make([]model.SearchResult, 0, len(items))
for _, item := range items {
result, ok := convertResult(item)View on GitHub (pinned to beaa561337)