fish2018/pansou · error
重试 次后仍然失败
Error message
重试 %d 次后仍然失败: %w
What it means
Qingying plugin's doRequestWithRetry wraps the last error after exhausting maxRetries attempts. It means the request failed on every try with a transport-level error; the final underlying error is preserved via %w. Callers fetchSearchResults and processDetailPage wrap it further.
Solutions
- Unwrap lastErr to classify the root cause (errors.As for net.Error timeout, *url.Error, syscall.ECONNREFUSED).
- Test the exact URL with curl to confirm whether the site or the local network is at fault.
- Increase maxRetries/timeout for transient slowness; add exponential backoff between attempts.
- Configure a proxy or rotate exit IPs if the site blocks this client; skip failing URLs gracefully in callers.
Example fix
// before
return nil, fmt.Errorf("重试 %d 次后仍然失败: %w", maxRetries, lastErr)
// after
var nerr net.Error
if errors.As(lastErr, &nerr) && nerr.Timeout() {
return nil, fmt.Errorf("重试 %d 次后仍然失败(请求超时): %w", maxRetries, lastErr)
}
return nil, fmt.Errorf("重试 %d 次后仍然失败: %w", maxRetries, lastErr) Defensive patterns
Strategy: fallback
Validate before calling
u, _ := url.Parse(baseURL)
conn, err := net.DialTimeout("tcp", net.JoinHostPort(u.Hostname(), "443"), 5*time.Second)
if err != nil {
log.Println("site unreachable, using cached results")
return
}
conn.Close() 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 nerr net.Error
if errors.As(err, &nerr) && nerr.Timeout() {
log.Println("qingying timed out after retries; serving cache")
}
return cachedResults, nil
} Prevention
- Keep cached/last-good results as a fallback for search failures.
- Classify the unwrapped cause (timeout vs refused vs TLS) before retrying.
- Use exponential backoff rather than tight retry loops.
- Diversify sources so one unreachable site degrades gracefully.
When it happens
Trigger: All maxRetries attempts inside the retry loop returned err — DNS failure, connection refused/reset, TLS error, or per-attempt context timeout — for either the search request or a detail page request.
Common situations: The target site is unreachable from this network (blocked or down); anti-bot drops connections; slow responses exceed the timeout on every attempt; transient ISP/network outage.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/9cac0d7a002fd092.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/qingying/qingying.go:448
for i := 0; i < maxRetries; i++ {
if i > 0 {
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)
}
View on GitHub (pinned to beaa561337)