{"record":{"id":"6930bf3da3cc413a","repo":"fish2018/pansou","slug":"decode-response-failed-page-d-type-s-w","errorCode":null,"errorMessage":"decode response failed (page %d, type %s): %w","messagePattern":"decode response failed \\(page (.+?), type (.+?)\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/sousou/sousou.go","lineNumber":444,"sourceCode":"\t\t\t\terrChan <- fmt.Errorf(\"HTTP error (page %d, type %s): %d\", pageNum, diskType, resp.StatusCode)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// 读取响应体\n\t\t\trespBody, err := io.ReadAll(resp.Body)\n\t\t\tif err != nil {\n\t\t\t\tdebugLog(\"读取响应失败 (page %d, type %s): %v\", pageNum, diskType, err)\n\t\t\t\terrChan <- fmt.Errorf(\"read response body failed (page %d, type %s): %w\", pageNum, diskType, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tdebugLog(\"响应内容 (page %d, type %s, 前500字符): %s\", pageNum, diskType, string(respBody[:min(500, len(respBody))]))\n\n\t\t\t// 解析响应\n\t\t\tvar apiResp SousouResponse\n\t\t\tif err := json.Unmarshal(respBody, &apiResp); err != nil {\n\t\t\t\tdebugLog(\"JSON解析失败 (page %d, type %s): %v\", pageNum, diskType, err)\n\t\t\t\terrChan <- fmt.Errorf(\"decode response failed (page %d, type %s): %w\", pageNum, diskType, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// 检查响应状态\n\t\t\tif apiResp.Code != 200 {\n\t\t\t\tdebugLog(\"API返回错误 (page %d, type %s): code=%d, msg=%s\", pageNum, diskType, apiResp.Code, apiResp.Msg)\n\t\t\t\terrChan <- fmt.Errorf(\"API returned error (page %d, type %s): %s\", pageNum, diskType, apiResp.Msg)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tdebugLog(\"成功获取第 %d 页数据 (type %s)，共 %d 条结果\", pageNum, diskType, len(apiResp.Data.List))\n\n\t\t\t// 将结果发送到通道\n\t\t\tresultChan <- apiResp.Data.List\n\t\t}(page)\n\t}\n\n\t// 启动一个goroutine等待所有页面请求完成并关闭通道","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/sousou/sousou.go#L426-L462","documentation":"json.Unmarshal failed on a sousou response body for a specific page/diskType. The server returned 200 but the body was not valid SousouResponse JSON — usually an anti-bot interstitial, truncated body, or schema change. Reported per-shard via errChan.","triggerScenarios":"The API returned HTML (error page, WAF challenge, login page), an empty body, or truncated JSON — anything json.Unmarshal cannot decode into SousouResponse.","commonSituations":"Cloudflare/anti-bot HTML page returned with status 200; API endpoint changed its response schema; body truncated by a proxy; site moved and a redirect's HTML is captured.","solutions":["Log the first 500 bytes of respBody (the debugLog already does) to identify HTML vs truncated JSON","Check whether a WAF challenge page is being returned and add required cookies/headers","Update the SousouResponse struct if the API response schema changed","Validate the body looks like JSON (e.g. starts with '{') and return a clearer message when it does not"],"exampleFix":"// before\nvar apiResp SousouResponse\nif err := json.Unmarshal(respBody, &apiResp); err != nil {\n    errChan <- fmt.Errorf(\"decode response failed (page %d, type %s): %w\", pageNum, diskType, err)\n    return\n}\n// after\nif len(respBody) > 0 && respBody[0] != '{' && respBody[0] != '[' {\n    errChan <- fmt.Errorf(\"non-JSON response (page %d, type %s), likely WAF page: %.100s\", pageNum, diskType, respBody)\n    return\n}\nvar apiResp SousouResponse\nif err := json.Unmarshal(respBody, &apiResp); err != nil {\n    errChan <- fmt.Errorf(\"decode response failed (page %d, type %s): %w\", pageNum, diskType, err)\n    return\n}","handlingStrategy":"type-guard","validationCode":"trimmed := bytes.TrimSpace(respBody)\nif len(trimmed) == 0 || (trimmed[0] != '{' && trimmed[0] != '[') {\n    return fmt.Errorf(\"non-JSON body: %.100s\", trimmed)\n}","typeGuard":"func looksLikeJSON(b []byte) bool {\n    b = bytes.TrimSpace(b)\n    return len(b) > 0 && (b[0] == '{' || b[0] == '[')\n}","tryCatchPattern":"var apiResp SousouResponse\nif err := json.Unmarshal(respBody, &apiResp); err != nil {\n    return fmt.Errorf(\"unexpected sousou response: %w\", err) // inspect logged body\n}","preventionTips":["Keep the debugLog of the first 500 bytes enabled to diagnose HTML vs JSON","Update SousouResponse struct when the API schema changes","Detect WAF/challenge pages early and add required cookies","Never assume status 200 implies a JSON body"],"tags":["json","parsing","api"],"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"}