{"record":{"id":"bc3222aeed88ad7f","repo":"fish2018/pansou","slug":"s-unexpected-status-code-d-on-page-d","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/discourse/discourse.go","lineNumber":232,"sourceCode":"\t\tresp, err := p.scraper.Get(searchURL)\n\t\tif err != nil {\n\t\t\t// 如果已经获取到一些结果，返回已有结果而不是报错\n\t\t\tif len(allResults) > 0 {\n\t\t\t\tfmt.Printf(\"[%s] Warning: failed to fetch page %d: %v\\n\", p.Name(), currentPage, 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(), currentPage, err)\n\t\t}\n\n\t\t// 检查HTTP状态码\n\t\tif resp.StatusCode != 200 {\n\t\t\tresp.Body.Close()\n\t\t\t// 如果已经获取到一些结果，返回已有结果\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, currentPage)\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, currentPage)\n\t\t}\n\n\t\t// 读取响应体\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\tfmt.Printf(\"[%s] Warning: failed to read page %d: %v\\n\", p.Name(), currentPage, err)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"[%s] read response failed on page %d: %w\", p.Name(), currentPage, err)\n\t\t}\n\n\t\t// 解析JSON响应\n\t\tvar searchResp SearchResponse\n\t\tif err := json.Unmarshal(body, &searchResp); err != nil {\n\t\t\tif len(allResults) > 0 {\n\t\t\t\tfmt.Printf(\"[%s] Warning: failed to parse page %d: %v\\n\", p.Name(), currentPage, err)","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/discourse/discourse.go#L214-L250","documentation":"searchImpl paginates the Discourse /search.json API. If a page returns a non-2xx status code and no results have been accumulated yet, the plugin aborts and returns this error wrapping the plugin name, status code, and page number. If some results were already collected, it only logs a warning and stops instead.","triggerScenarios":"Calling Search (via searchImpl) when a Discourse search page request returns e.g. 403, 429, or 500 on the first page fetched (allResults empty).","commonSituations":"Site blocks requests due to missing/rotated Cloudflare clearance, rate limiting from too-fast pagination, forum being temporarily down, or an incorrect base URL hitting an error page.","solutions":["Check the status code printed in the error; if 403/503 the site's Cloudflare protection likely rejected the request — verify scraper/cloudscraper initialization and cookies","Reduce pagination speed or page count to avoid 429 rate limiting","Verify the configured Discourse base URL is correct and reachable in a browser","Retry later if the forum is temporarily down (5xx)","If partial results are acceptable, rely on the warning path (results already present) instead of failing"],"exampleFix":"// before\nif resp.StatusCode != 200 {\n    return nil, fmt.Errorf(\"[%s] unexpected status code: %d on page %d\", p.Name(), resp.StatusCode, currentPage)\n}\n// after\nif resp.StatusCode == 429 {\n    time.Sleep(retryBackoff)\n    continue // retry the same page\n} else if resp.StatusCode != 200 {\n    return nil, fmt.Errorf(\"[%s] unexpected status code: %d on page %d\", p.Name(), resp.StatusCode, currentPage)\n}","handlingStrategy":"retry","validationCode":"// optionally pre-check the site is reachable\nresp, err := http.Get(baseURL + \"/about.json\")\nif err != nil || resp.StatusCode != 200 {\n    return fmt.Errorf(\"discourse site unreachable: status=%d err=%v\", statusOf(resp), err)\n}","typeGuard":null,"tryCatchPattern":"links, err := plugin.Search(query)\nif err != nil {\n    if strings.Contains(err.Error(), \"unexpected status code\") {\n        // parse code, backoff and retry once for 429/5xx\n        time.Sleep(backoff)\n        links, err = plugin.Search(query)\n    }\n    if err != nil {\n        return fmt.Errorf(\"search failed: %w\", err)\n    }\n}","preventionTips":["Keep request rates low to avoid 429s","Keep cloudscraper sessions/cookies fresh for Cloudflare-protected sites","Validate the configured forum base URL before searching","Handle partial results: the plugin warns instead of erroring once some pages succeeded"],"tags":["http","pagination","discourse","network"],"backgroundTag":"http-error-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"}