fish2018/pansou · error

重试 次后仍然失败

Error message

重试 %d 次后仍然失败: %w

What it means

This final error from yunsou's doRequestWithRetry means every one of maxRetries attempts failed — either with a network error or a non-200 status (the last failure is wrapped via %w). The page fetch is abandoned and fetchPage surfaces it as '第%d页搜索请求失败'. It is the plugin's definitive 'upstream unreachable or rejecting us' signal.

Solutions

  1. Read the wrapped lastErr to distinguish network failure vs bad status code.
  2. Test reachability manually with curl using the same headers.
  3. Increase maxRetries and add exponential backoff between attempts.
  4. If IP is blocked, use a proxy or wait for the block to expire.
  5. Fail gracefully: skip the failing page instead of aborting the entire search.

Example fix

// before
return nil, fmt.Errorf("重试 %d 次后仍然失败: %w", maxRetries, lastErr)
// after
for attempt := 1; attempt <= maxRetries; attempt++ {
    ...
    time.Sleep(time.Duration(attempt) * time.Second) // exponential backoff
}
return nil, fmt.Errorf("重试 %d 次后仍然失败: %w", maxRetries, lastErr)
Defensive patterns

Strategy: retry

Validate before calling

func siteUp(u string) bool {
    c := &http.Client{Timeout: 5 * time.Second}
    resp, err := c.Head(u)
    return err == nil && resp.StatusCode < 500
}

Try / catch

results, err := plugin.Search(keyword)
if err != nil {
    var retried *RetryExhaustedError
    if errors.As(err, &retried) {
        return fallbackPlugin.Search(keyword) // switch to another plugin/mirror
    }
    return nil, err
}

Prevention

When it happens

Trigger: Loop in doRequestWithRetry completes with resp==nil or status!=200 on all attempts; lastErr (network error or '状态码 %d') is wrapped and returned to fetchPage.

Common situations: Sustained site outage, IP blocked by the site's firewall, no internet connection, or DNS misconfiguration in a container/CI environment.

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/623d27284779b29b. Report an issue: GitHub.

Appendix: source

Thrown at plugin/yunsou/yunsou.go:156

func (p *YunsouAsyncPlugin) doRequestWithRetry(req *http.Request, client *http.Client) (*http.Response, error) {
	var lastErr error
	for attempt := 0; attempt < maxRetries; attempt++ {
		if attempt > 0 {
			time.Sleep(time.Duration(1<<(attempt-1)) * 200 * time.Millisecond)
		}
		resp, err := client.Do(req.Clone(req.Context()))
		if err == nil && resp.StatusCode == http.StatusOK {
			return resp, nil
		}
		if resp != nil {
			lastErr = fmt.Errorf("状态码 %d", resp.StatusCode)
			resp.Body.Close()
		} else {
			lastErr = err
		}
	}
	return nil, fmt.Errorf("重试 %d 次后仍然失败: %w", maxRetries, lastErr)
}

func (p *YunsouAsyncPlugin) parseSearchResults(doc *goquery.Document) []model.SearchResult {
	results := make([]model.SearchResult, 0)
	doc.Find(".list .item").Each(func(_ int, item *goquery.Selection) {
		if len(results) >= maxResults {
			return
		}
		title, _ := item.Attr("data-title")
		if title == "" {
			title = item.Find(".title").First().Text()
		}
		title = cleanText(html.UnescapeString(title))
		if title == "" {
			return
		}

		shareURL, password := "", ""

View on GitHub (pinned to beaa561337)