fish2018/pansou · error
请求重试 次仍失败
Error message
请求重试 %d 次仍失败: %w
What it means
This error is returned by doRequestWithRetry in the yulinshufa plugin after all retry attempts have been exhausted. It wraps the last underlying error (either a non-2xx status code reported as "状态码: %d" or the final transport error) so callers see both the retry count and root cause. It means the upstream yulinshufa site could not be reached or did not return a successful response within maxRetries attempts.
Solutions
- Inspect the wrapped %w cause to identify whether it was a status code or a transport error
- Curl the target URL from the same host to check connectivity and whether the site is blocking you
- Increase retry count or add backoff delays between retries in doRequestWithRetry
- Add/refresh required headers or cookies (User-Agent, anti-bot tokens) used by the plugin
- If the site bans by IP, route through a proxy or wait out the rate limit
Example fix
// before
items, err := fetchSearchItems(keyword) // opaque retry-exhausted error
// after
if errors.Is(err, context.DeadlineExceeded) {
log.Warn("yulinshufa timeout, backing off")
time.Sleep(5 * time.Second)
}
items, err := fetchSearchItems(keyword) Defensive patterns
Strategy: retry
Validate before calling
// preflight
resp, err := http.Head("https://target-site.example/search")
if err != nil || resp.StatusCode >= 400 {
log.Warn("upstream unreachable, skipping yulinshufa search")
} Type guard
func isRetryExhausted(err error) bool {
return err != nil && strings.Contains(err.Error(), "仍失败")
} Try / catch
items, err := fetchSearchItems(ctx, keyword)
if err != nil {
var retried *RetryExhaustedError
if errors.As(err, &retried) {
log.Warn("yulinshufa failed after retries", "cause", errors.Unwrap(err))
return fallbackSearch(ctx, keyword)
}
return err
} Prevention
- Always inspect errors.Unwrap(err) to distinguish status codes from transport errors
- Add exponential backoff between retries
- Keep User-Agent/cookies fresh to avoid anti-bot blocks
- Monitor upstream availability and circuit-break when it degrades
When it happens
Trigger: fetchSearchItems or getDetailResult calls doRequestWithRetry and every attempt fails — e.g. the target site returns 403/429/5xx on all retries, DNS failure, TLS errors, or network timeouts.
Common situations: The site is down or blocking the scraper (IP rate-limit/ban), a required cookie/anti-bot token is missing, the container has no internet or broken DNS, or the site changed its URL/anti-scraping behavior.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/d43571866e6d8756.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/yulinshufa/yulinshufa.go:753
if attempt > 0 {
backoff := time.Duration(1<<uint(attempt-1)) * 200 * time.Millisecond
time.Sleep(backoff)
p.debugf("重试第 %d 次, url=%s", attempt+1, req.URL.String())
}
resp, err := client.Do(req.Clone(req.Context()))
if err == nil && resp.StatusCode == http.StatusOK {
return resp, nil
}
if resp != nil {
resp.Body.Close()
lastErr = fmt.Errorf("状态码: %d", resp.StatusCode)
} else {
lastErr = err
}
}
return nil, fmt.Errorf("请求重试 %d 次仍失败: %w", maxRetries, lastErr)
}
func parseDebugFlag() bool {
value := strings.ToLower(strings.TrimSpace(os.Getenv("YULINSHUFA_DEBUG")))
if value == "" {
return false
}
return value == "1" || value == "true" || value == "yes" || value == "on"
}
func (p *YulinshufaPlugin) debugf(format string, args ...interface{}) {
if p.debugMode {
log.Printf("[YULINSHUFA] "+format, args...)
}
}
View on GitHub (pinned to beaa561337)