fish2018/pansou · error
[ ] unexpected status code: on page
Error message
[%s] unexpected status code: %d on page %d
What it means
The search API returned a non-200 HTTP status code. If no results were collected yet, searchImpl aborts with this error naming the plugin, status code, and page; otherwise it breaks the pagination loop with a warning and returns partial results.
Solutions
- Log/inspect the status code — 403/503 usually means Cloudflare; 429 means slow down or add backoff
- Reduce request rate / pages fetched (maxPages) to avoid rate limiting
- Update cloudscraper or add proxies if the site hardened its protection
- Verify the API base URL is still valid (404 indicates the endpoint moved)
Example fix
// before
return nil, fmt.Errorf("[%s] unexpected status code: %d on page %d", p.Name(), resp.StatusCode, page)
// after
if resp.StatusCode == http.StatusTooManyRequests {
time.Sleep(retryAfterDelay)
return p.searchWithRetry(client, keyword, ext)
}
return nil, fmt.Errorf("[%s] unexpected status code: %d on page %d", p.Name(), resp.StatusCode, page) Defensive patterns
Strategy: retry
Validate before calling
resp, err := http.Get("https://www.panzun.cc/api/discussions?page[size]=1")
if err == nil && resp.StatusCode != 200 { /* degraded upstream, expect non-200 */ } Try / catch
results, err := plugin.Search(keyword, ext)
if err != nil {
if strings.Contains(err.Error(), "unexpected status code: 4") {
// client-side block: backoff or rotate proxy
} else if strings.Contains(err.Error(), "unexpected status code: 5") {
// upstream outage: retry later
}
} Prevention
- Throttle request rate across pages to avoid 429
- Keep cloudscraper updated to survive Cloudflare changes
- Treat partial results as valid when later pages fail
When it happens
Trigger: GET of the Flarum discussions API (page N, zero prior results) returns 403/429/500/etc., typically Cloudflare blocking, rate limiting, or upstream server errors.
Common situations: IP rate-limited by the site; Cloudflare challenge not passed by cloudscraper; site renamed/moved API and returns 404; temporary 5xx outage.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/b5b6e3defa61895e.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/panzun/panzun.go:135
offset := (page - 1) * pageSize
searchURL := fmt.Sprintf("%s/discussions?filter[q]=%s&page[offset]=%d", apiBase, url.QueryEscape(keyword), offset)
resp, err := p.scraper.Get(searchURL)
if err != nil {
if len(allResults) > 0 {
fmt.Printf("[%s] Warning: failed to fetch page %d: %v\n", p.Name(), page, err)
break
}
return nil, fmt.Errorf("[%s] search request failed on page %d: %w", p.Name(), page, err)
}
if resp.StatusCode != http.StatusOK {
resp.Body.Close()
if len(allResults) > 0 {
fmt.Printf("[%s] Warning: unexpected status code %d on page %d\n", p.Name(), resp.StatusCode, page)
break
}
return nil, fmt.Errorf("[%s] unexpected status code: %d on page %d", p.Name(), resp.StatusCode, page)
}
body, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
if len(allResults) > 0 {
break
}
return nil, fmt.Errorf("[%s] failed to read response on page %d: %w", p.Name(), page, err)
}
var searchResp SearchResponse
if err := jsonutil.Unmarshal(body, &searchResp); err != nil {
if len(allResults) > 0 {
break
}
return nil, fmt.Errorf("[%s] failed to parse response on page %d: %w", p.Name(), page, err)
}View on GitHub (pinned to beaa561337)