fish2018/pansou · error
重试 次后仍然失败
Error message
重试 %d 次后仍然失败: %w
What it means
nsgame's doRequestWithRetry exhausts all maxRetries attempts without success and returns the final underlying error wrapped as '仍然失败 after N retries'. This is a terminal aggregate error: the actual root cause is inside the wrapped lastErr (transport error or HTTP status code).
Solutions
- Unwrap with %w / errors.Unwrap to see the root lastErr before treating this as the cause.
- Test the target URL directly with curl to determine if the outage is site-side or client-side.
- Increase backoff duration between retries; rapid retries against a rate-limiter prolong the ban.
- Add jitter and cap concurrency if many goroutines hammer the site simultaneously.
- Configure a proxy or rotate exit IPs if the site blocks your datacenter IP range.
Example fix
// before
return nil, fmt.Errorf("重试 %d 次后仍然失败: %w", maxRetries, lastErr)
// after
return nil, fmt.Errorf("重试 %d 次后仍然失败 (last: %v): %w", maxRetries, time.Since(start).Round(time.Second), lastErr) Defensive patterns
Strategy: retry
Validate before calling
// preflight reachability check before invoking the plugin
resp, err := http.Head("https://nsthwj.cn/")
if err != nil || resp.StatusCode != 200 { /* site unreachable — fix network first */ } Type guard
null
Try / catch
results, err := p.Search(keyword)
if err != nil {
if strings.Contains(err.Error(), "仍然失败") {
var root error
for e := err; e != nil; e = errors.Unwrap(e) { root = e }
log.Printf("retries exhausted, root: %v", root)
}
} Prevention
- Unwrap the aggregate error to see the real cause before reacting.
- Add jittered exponential backoff so retries outlast transient outages.
- Rotate proxies if a single IP is being rate-limited across all attempts.
- Reduce concurrent goroutines hitting the same site.
When it happens
Trigger: searchImpl or fetchDetail issues a request that fails on every retry iteration — persistent network failure, sustained non-200 responses, or server-side blocking across all attempts within the retry window.
Common situations: Site nsthwj.cn is down for maintenance, IP is rate-limited/banned so all retries get 403/429, or DNS/network outage in the deployment environment lasting longer than the retry sequence.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/28aedee7e0d2c84f.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/nsgame/nsgame.go:510
// 克隆请求避免并发问题
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
if lastErr == nil {
lastErr = fmt.Errorf("HTTP 状态码 %d", resp.StatusCode)
}
}
return nil, fmt.Errorf("重试 %d 次后仍然失败: %w", maxRetries, lastErr)
}
View on GitHub (pinned to beaa561337)