fish2018/pansou · error

unexpected HTTP status

Error message

unexpected HTTP status: %s

What it means

doRequestWithRetry in the Meitizy plugin only accepts HTTP 200 responses; any other status (e.g. 403, 429, 5xx) is recorded as "unexpected HTTP status: %s" using resp.Status. It is a retry wrapper around client.Do called by searchImpl and fetchDetailLinks; a non-200 on each attempt means the upstream meitizy endpoint rejected the request or is failing.

Solutions

  1. Check the full wrapped status string (e.g. 429 Too Many Requests) to identify the class of problem; for 429 back off and retry later
  2. Inspect and refresh any required cookies/anti-bot tokens or headers for meitizy; 403 usually means WAF blocking
  3. Verify the upstream endpoint URL is still valid (404/301 suggest the site changed)
  4. If 5xx, treat as upstream outage and retry after a delay; check site availability manually

Example fix

// before: only 200 accepted, error loses status code detail beyond resp.Status
if err == nil && resp.StatusCode == 200 {
	return resp, nil
}
// after: log body snippet for non-200 to aid diagnosis
if err == nil && resp.StatusCode != 200 {
	b, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
	lastErr = fmt.Errorf("unexpected HTTP status: %s body=%q", resp.Status, b)
}
Defensive patterns

Strategy: retry

Validate before calling

if resp.StatusCode == http.StatusTooManyRequests {
	if ra, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil {
		time.Sleep(time.Duration(ra) * time.Second)
	}
}

Try / catch

resp, err := doRequestWithRetry(req, client)
if err != nil {
	var statusErr *fmt.Errorf
	if errors.As(err, &statusErr) && strings.Contains(err.Error(), "unexpected HTTP status") {
		// handle non-200: back off, refresh credentials, or degrade
	}
	return nil, err
}

Prevention

When it happens

Trigger: Any call to p.searchImpl or p.fetchDetailLinks where the meitizy server answers with a status other than 200 on all retry attempts: rate limiting (429), WAF/anti-bot blocking (403), gateway errors (502/503), or a moved endpoint returning 404.

Common situations: The site's anti-scraping protection blocks the plugin's requests (missing/invalid cookies or fingerprint), the target URL changed, heavy keyword use triggers rate limiting, or the upstream service is temporarily down.

Related errors


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

Appendix: source

Thrown at plugin/meitizy/meitizy.go:393

		if req.Body != nil {
			// 读取原始body
			bodyBytes, err := io.ReadAll(req.Body)
			if err != nil {
				lastErr = err
				continue
			}
			req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
			reqClone.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
		}

		resp, err := client.Do(reqClone)
		if err == nil && resp.StatusCode == 200 {
			return resp, nil
		}

		if resp != nil {
			if err == nil {
				lastErr = fmt.Errorf("unexpected HTTP status: %s", resp.Status)
			}
			resp.Body.Close()
		}
		if err != nil {
			lastErr = err
		}
	}

	return nil, fmt.Errorf("[%s] 重试 %d 次后仍然失败: %w", p.Name(), maxRetries, lastErr)
}

View on GitHub (pinned to beaa561337)