fish2018/pansou · error
重试 次后仍然失败
Error message
重试 %d 次后仍然失败: %w
What it means
Pianku plugin's doRequestWithRetry wraps the last error after exhausting MaxRetries HTTP attempts. It signals that every retry of the request failed (network errors, timeouts, or non-recoverable transport failures), and the final underlying error is preserved via %w. Callers searchImpl and fetchDetailPageLinks propagate this up as a failed search.
Solutions
- Check basic connectivity to the target host (curl -v the search URL) to see if the site is reachable from this machine.
- Increase MaxRetries and/or the per-request timeout constants in plugin/pianku/pianku.go if failures are transient slowness.
- Inspect the wrapped lastErr (errors.Unwrap / %v) to identify the root cause — timeout vs refused vs TLS — and fix accordingly.
- Configure a working HTTP proxy for the client if the host is blocked from this network, or rotate exit IPs if rate-limited.
Example fix
// before
return nil, fmt.Errorf("重试 %d 次后仍然失败: %w", MaxRetries, lastErr)
// after
var netErr net.Error
if errors.As(lastErr, &netErr) && netErr.Timeout() {
return nil, fmt.Errorf("重试 %d 次后仍然失败(超时): %w", MaxRetries, lastErr)
}
return nil, fmt.Errorf("重试 %d 次后仍然失败: %w", MaxRetries, lastErr) Defensive patterns
Strategy: retry
Validate before calling
// pre-check reachability before invoking the plugin search
resp, err := http.Head("https://www.pianku.tv")
if err != nil || resp.StatusCode >= 500 {
log.Println("pianku site unreachable, skipping search")
return
} Type guard
func isRetryExhausted(err error) bool {
return err != nil && strings.Contains(err.Error(), "重试")
} Try / catch
results, err := plugin.Search(keyword)
if err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
// retry later with backoff
} else {
log.Printf("pianku search failed permanently: %v", err)
}
return fallbackResults, nil
} Prevention
- Check site reachability before running bulk searches.
- Tune MaxRetries and timeouts for your network conditions.
- Inspect the wrapped cause with errors.Unwrap to route handling.
- Keep multiple plugin sources as fallbacks so one dead site doesn't break the app.
When it happens
Trigger: Any request issued through doRequestWithRetry (from searchImpl or fetchDetailPageLinks) where all MaxRetries attempts fail with a transport-level error: connection reset, TLS handshake failure, DNS resolution failure, or context deadline exceeded inside the retry loop.
Common situations: Site is down or blocking the scraper (rate limiting, IP ban); corporate proxy/firewall dropping HTTPS; slow network causing per-attempt timeouts; the site changed its TLS config so the client handshake fails repeatedly.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/3a56d01a0882f09d.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/pianku/pianku.go:221
backoff := time.Duration(1<<uint(i-1)) * 200 * time.Millisecond
time.Sleep(backoff)
}
// 克隆请求避免并发问题
reqClone := req.Clone(req.Context())
resp, err := client.Do(reqClone)
if err == nil && resp.StatusCode == 200 {
return resp, nil
}
if resp != nil {
resp.Body.Close()
}
lastErr = err
}
return nil, fmt.Errorf("重试 %d 次后仍然失败: %w", MaxRetries, lastErr)
}
// extractSearchResults 提取搜索结果
func (p *PiankuPlugin) extractSearchResults(doc *goquery.Document) []model.SearchResult {
var results []model.SearchResult
// 查找搜索结果容器
doc.Find(".sr_lists dl").Each(func(i int, s *goquery.Selection) {
result := p.extractSingleResult(s)
if result.UniqueID != "" && len(result.Links) > 0 {
results = append(results, result)
}
})
return results
}
// extractSingleResult 提取单个搜索结果View on GitHub (pinned to beaa561337)