fish2018/pansou · error

HTTP

Error message

HTTP %d

What it means

Internal retry-loop error in fetchBody: a retry attempt received an HTTP response with a non-2xx status code. This becomes lastErr for the attempt and, if all attempts fail, is the cause wrapped in the error returned by fetchDocument. Not normally seen directly by callers.

Solutions

  1. Note the exact status code: 429 → slow down; 403 → fix headers/cookies; 5xx → upstream outage.
  2. Update request headers (User-Agent, Referer, cookies) to pass bot checks.
  3. Lengthen the backoff schedule or retry count for flaky upstreams.
  4. Verify the URL still exists after any site redesign.
Defensive patterns

Strategy: retry

Validate before calling

resp, err := http.Get(targetURL)
if err == nil && resp.StatusCode != 200 {
    log.Printf("upstream status %d before calling plugin", resp.StatusCode)
}

Try / catch

if err := fetchDocument(...); err != nil {
    if strings.Contains(err.Error(), "HTTP ") {
        code := extractStatus(err)
        if code == 429 {
            time.Sleep(rateLimitCooldown)
        }
    }
    return err
}

Prevention

When it happens

Trigger: fetchBody: client.Do returned no transport error but resp.StatusCode was not a success code on the final attempt; each failing attempt closes the body and backs off exponentially (200ms * 2^attempt).

Common situations: Rate limiting (429), CDN 502/503 during site load spikes, 403 from bot detection or missing cookies, 404 after site URL restructure.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/48faa00236e2bb5a. Report an issue: GitHub.

Appendix: source

Thrown at plugin/gaoqing888/gaoqing888.go:350

		req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
		req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
		req.Header.Set("Connection", "keep-alive")
		req.Header.Set("Referer", referer)

		resp, err := client.Do(req)
		if err == nil && resp.StatusCode == http.StatusOK {
			defer resp.Body.Close()
			data, readErr := io.ReadAll(resp.Body)
			cancel()
			return data, readErr
		}
		if resp != nil {
			resp.Body.Close()
		}
		if err != nil {
			lastErr = err
		} else {
			lastErr = fmt.Errorf("HTTP %d", resp.StatusCode)
		}
		cancel()
		if attempt < maxRetries-1 {
			time.Sleep(200 * time.Millisecond * time.Duration(1<<attempt))
		}
	}
	return nil, lastErr
}

View on GitHub (pinned to beaa561337)