{"record":{"id":"c84a4c7fdbc3aa90","repo":"fish2018/pansou","slug":"s-json-w","errorCode":null,"errorMessage":"[%s] JSON解析失败: %w","messagePattern":"\\[(.+?)\\] JSON解析失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/ikantv/ikantv.go","lineNumber":100,"sourceCode":"\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"[%s] 请求返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 读取响应失败: %w\", p.Name(), err)\n\t}\n\n\tvar apiResp apiResponse\n\tif err := json.Unmarshal(body, &apiResp); err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] JSON解析失败: %w\", p.Name(), err)\n\t}\n\tif apiResp.Code != 0 {\n\t\treturn nil, fmt.Errorf(\"[%s] API错误: %s\", p.Name(), apiResp.Message)\n\t}\n\n\tresults := convertResults(apiResp.Data)\n\treturn plugin.FilterResultsByKeyword(results, keyword), nil\n}\n\nfunc convertResults(items []apiItem) []model.SearchResult {\n\tresults := make([]model.SearchResult, 0, len(items))\n\tfor _, item := range items {\n\t\tresult, ok := convertResult(item)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tresults = append(results, result)\n\t}","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/ikantv/ikantv.go#L82-L118","documentation":"ikantv plugin's doSearch throws this when json.Unmarshal(body, &apiResp) fails to decode the response into apiResponse. The body is not valid JSON or its field types conflict with the apiResponse struct.","triggerScenarios":"The 200-status body is HTML (anti-bot interstitial), empty, truncated, or JSON with mismatched types (e.g. code delivered as string not number), so unmarshalling into apiResponse errors.","commonSituations":"Site changed its API shape or now serves a challenge page instead of JSON; CDN/WAF injects HTML; an upstream outage returns an error page with status 200.","solutions":["Dump/log the raw body on failure to see whether it is JSON, HTML, or empty.","Compare the body against the apiResponse struct — update field names/types if the API schema changed.","Check whether the API now requires different headers/cookies and update the request.","Add content-type validation before unmarshalling to give a clearer error on HTML responses."],"exampleFix":"// before\nvar apiResp apiResponse\nif err := json.Unmarshal(body, &apiResp); err != nil {\n\treturn nil, fmt.Errorf(\"[%s] JSON解析失败: %w\", p.Name(), err)\n}\n// after\nvar apiResp apiResponse\nif err := json.Unmarshal(body, &apiResp); err != nil {\n\treturn nil, fmt.Errorf(\"[%s] JSON解析失败: %s...: %w\", p.Name(), string(body[:min(200, len(body))]), err)\n}","handlingStrategy":"type-guard","validationCode":"// verify the response is JSON before decoding\nif !strings.Contains(resp.Header.Get(\"Content-Type\"), \"json\") {\n\treturn fmt.Errorf(\"ikantv returned non-JSON content-type: %q\", resp.Header.Get(\"Content-Type\"))\n}","typeGuard":"func isJSONBody(b []byte) bool {\n\tt := bytes.TrimSpace(b)\n\treturn len(t) > 0 && (t[0] == '{' || t[0] == '[')\n}","tryCatchPattern":"results, err := p.doSearch(ctx, keyword)\nif err != nil && strings.Contains(err.Error(), \"JSON解析失败\") {\n\t// log the raw body once to determine HTML-vs-schema drift, then update the struct\n\tlog.Printf(\"ikantv response not JSON — check API contract: %v\", err)\n}","preventionTips":["Dump raw bodies on decode failure to distinguish challenge pages from schema drift","Validate content-type before unmarshalling","Keep apiResponse struct aligned with the live API (field names and JSON types)","Re-run integration tests against the upstream after site updates"],"tags":["json","go","unmarshal","response-parsing"],"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"}