fish2018/pansou · error
[ ] failed to parse response on page
Error message
[%s] failed to parse response on page %d: %w
What it means
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.
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
Example fix
// before
return nil, fmt.Errorf("[%s] failed to parse response on page %d: %w", p.Name(), page, err)
// after
if jsonutil.Valid(body) {
log.Printf("[%s] unexpected schema: %.200s", p.Name(), body)
} else {
log.Printf("[%s] non-JSON response (Cloudflare?): %.200s", p.Name(), body)
}
return nil, fmt.Errorf("[%s] failed to parse response on page %d: %w", p.Name(), page, err) Defensive patterns
Strategy: fallback
Validate before calling
resp, _ := http.Get("https://www.panzun.cc/api/discussions?page[size]=1")
b, _ := io.ReadAll(resp.Body)
if !json.Valid(b) { /* schema/anti-bot issue, skip plugin */ } Type guard
func looksLikeFlarumResponse(body []byte) bool {
var probe struct { Data []json.RawMessage `json:"data"` }
return json.Unmarshal(body, &probe) == nil
} Try / catch
results, err := plugin.Search(keyword, ext)
if err != nil {
if strings.Contains(err.Error(), "failed to parse response") {
// upstream schema change or Cloudflare page: log body snippet, fall back to other plugins
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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).
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/20446264d54af729.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/panzun/panzun.go:152
}
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)
}
pageResults, err := p.convertDiscussionsToResults(client, searchResp.Data)
if err != nil {
fmt.Printf("[%s] Warning: detail parse failed on page %d: %v\n", p.Name(), page, err)
}
for _, result := range pageResults {
if result.UniqueID == "" || seenIDs[result.UniqueID] {
continue
}
seenIDs[result.UniqueID] = true
allResults = append(allResults, result)
}
if searchResp.Links["next"] == "" {
break
}View on GitHub (pinned to beaa561337)