{"record":{"id":"20446264d54af729","repo":"fish2018/pansou","slug":"s-failed-to-parse-response-on-page-d-w","errorCode":null,"errorMessage":"[%s] failed to parse response on page %d: %w","messagePattern":"\\[(.+?)\\] failed to parse response on page (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/panzun/panzun.go","lineNumber":152,"sourceCode":"\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}\n\n\t\tpageResults, err := p.convertDiscussionsToResults(client, searchResp.Data)\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"[%s] Warning: detail parse failed on page %d: %v\\n\", p.Name(), page, err)\n\t\t}\n\n\t\tfor _, result := range pageResults {\n\t\t\tif result.UniqueID == \"\" || seenIDs[result.UniqueID] {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tseenIDs[result.UniqueID] = true\n\t\t\tallResults = append(allResults, result)\n\t\t}\n\n\t\tif searchResp.Links[\"next\"] == \"\" {\n\t\t\tbreak\n\t\t}","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/panzun/panzun.go#L134-L170","documentation":"jsonutil.Unmarshal failed to decode the search page body into SearchResponse. If no earlier pages produced results the search fails outright with this wrapped error; otherwise the loop breaks and partial results are returned.","triggerScenarios":"The panzun.cc discussions endpoint returns HTML (Cloudflare interstitial or error page), an empty body, or a changed JSON schema instead of the expected {links,data,included} Flarum JSONAPI payload on the first page.","commonSituations":"Cloudflare served a challenge page instead of JSON; site updated its API response shape; API returned an error JSON without the expected fields; CDN error page (502 HTML).","solutions":["Log the first bytes of the body on unmarshal failure to see what was actually returned","Validate the JSON structure of the current API response against the SearchResponse struct","Handle Cloudflare challenge pages (upgrade cloudscraper / use cookies)","If the schema changed, update the SearchResponse/Discussion struct tags"],"exampleFix":"// before\nreturn nil, fmt.Errorf(\"[%s] failed to parse response on page %d: %w\", p.Name(), page, err)\n// after\nif jsonutil.Valid(body) {\n    log.Printf(\"[%s] unexpected schema: %.200s\", p.Name(), body)\n} else {\n    log.Printf(\"[%s] non-JSON response (Cloudflare?): %.200s\", p.Name(), body)\n}\nreturn nil, fmt.Errorf(\"[%s] failed to parse response on page %d: %w\", p.Name(), page, err)","handlingStrategy":"fallback","validationCode":"resp, _ := http.Get(\"https://www.panzun.cc/api/discussions?page[size]=1\")\nb, _ := io.ReadAll(resp.Body)\nif !json.Valid(b) { /* schema/anti-bot issue, skip plugin */ }","typeGuard":"func looksLikeFlarumResponse(body []byte) bool {\n    var probe struct { Data []json.RawMessage `json:\"data\"` }\n    return json.Unmarshal(body, &probe) == nil\n}","tryCatchPattern":"results, err := plugin.Search(keyword, ext)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to parse response\") {\n        // upstream schema change or Cloudflare page: log body snippet, fall back to other plugins\n    }\n}","preventionTips":["Log the raw body on unmarshal failure to detect schema drift early","Pin/monitor the upstream API schema in CI smoke tests","Handle Cloudflare interstitials explicitly"],"tags":["go","json","parsing","scraping","plugin"],"backgroundTag":"json-unmarshal-failed","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"}