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

  1. Unwrap with %w / errors.Unwrap to see the root lastErr before treating this as the cause.
  2. Test the target URL directly with curl to determine if the outage is site-side or client-side.
  3. Increase backoff duration between retries; rapid retries against a rate-limiter prolong the ban.
  4. Add jitter and cap concurrency if many goroutines hammer the site simultaneously.
  5. 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

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)