{"record":{"id":"b5b6e3defa61895e","repo":"fish2018/pansou","slug":"s-unexpected-status-code-d-on-page-d-b5b6e3","errorCode":null,"errorMessage":"[%s] unexpected status code: %d on page %d","messagePattern":"\\[(.+?)\\] unexpected status code: (.+?) on page (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/panzun/panzun.go","lineNumber":135,"sourceCode":"\t\toffset := (page - 1) * pageSize\n\t\tsearchURL := fmt.Sprintf(\"%s/discussions?filter[q]=%s&page[offset]=%d\", apiBase, url.QueryEscape(keyword), offset)\n\n\t\tresp, err := p.scraper.Get(searchURL)\n\t\tif err != nil {\n\t\t\tif len(allResults) > 0 {\n\t\t\t\tfmt.Printf(\"[%s] Warning: failed to fetch page %d: %v\\n\", p.Name(), page, err)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"[%s] search request failed on page %d: %w\", p.Name(), page, err)\n\t\t}\n\n\t\tif resp.StatusCode != http.StatusOK {\n\t\t\tresp.Body.Close()\n\t\t\tif len(allResults) > 0 {\n\t\t\t\tfmt.Printf(\"[%s] Warning: unexpected status code %d on page %d\\n\", p.Name(), resp.StatusCode, page)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"[%s] unexpected status code: %d on page %d\", p.Name(), resp.StatusCode, page)\n\t\t}\n\n\t\tbody, err := io.ReadAll(resp.Body)\n\t\tresp.Body.Close()\n\t\tif err != nil {\n\t\t\tif len(allResults) > 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"[%s] failed to read response on page %d: %w\", p.Name(), page, err)\n\t\t}\n\n\t\tvar searchResp SearchResponse\n\t\tif err := jsonutil.Unmarshal(body, &searchResp); err != nil {\n\t\t\tif len(allResults) > 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"[%s] failed to parse response on page %d: %w\", p.Name(), page, err)\n\t\t}","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/panzun/panzun.go#L117-L153","documentation":"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.","triggerScenarios":"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.","commonSituations":"IP rate-limited by the site; Cloudflare challenge not passed by cloudscraper; site renamed/moved API and returns 404; temporary 5xx outage.","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)"],"exampleFix":"// before\nreturn nil, fmt.Errorf(\"[%s] unexpected status code: %d on page %d\", p.Name(), resp.StatusCode, page)\n// after\nif resp.StatusCode == http.StatusTooManyRequests {\n    time.Sleep(retryAfterDelay)\n    return p.searchWithRetry(client, keyword, ext)\n}\nreturn nil, fmt.Errorf(\"[%s] unexpected status code: %d on page %d\", p.Name(), resp.StatusCode, page)","handlingStrategy":"retry","validationCode":"resp, err := http.Get(\"https://www.panzun.cc/api/discussions?page[size]=1\")\nif err == nil && resp.StatusCode != 200 { /* degraded upstream, expect non-200 */ }","typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(keyword, ext)\nif err != nil {\n    if strings.Contains(err.Error(), \"unexpected status code: 4\") {\n        // client-side block: backoff or rotate proxy\n    } else if strings.Contains(err.Error(), \"unexpected status code: 5\") {\n        // upstream outage: retry later\n    }\n}","preventionTips":["Throttle request rate across pages to avoid 429","Keep cloudscraper updated to survive Cloudflare changes","Treat partial results as valid when later pages fail"],"tags":["go","http","scraping","status-code","plugin"],"backgroundTag":"http-non-200-response","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}