{"record":{"id":"75c7238fc6082afa","repo":"fish2018/pansou","slug":"decode-response-failed-w","errorCode":null,"errorMessage":"decode response failed: %w","messagePattern":"decode response failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/jikepan/jikepan.go","lineNumber":97,"sourceCode":"\treq.Header.Set(\"referer\", \"https://jikepan.xyz/\")\n\treq.Header.Set(\"User-Agent\", \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\")\n\t\n\t// 发送请求\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"request failed: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\t\n\t// 解析响应\n\tvar apiResp JikepanResponse\n\tbodyBytes, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read response body failed: %w\", err)\n\t}\n\t\n\tif err := json.Unmarshal(bodyBytes, &apiResp); err != nil {\n\t\treturn nil, fmt.Errorf(\"decode response failed: %w\", err)\n\t}\n\t\n\t// 检查响应状态\n\tif apiResp.Msg != \"success\" {\n\t\treturn nil, fmt.Errorf(\"API returned error: %s\", apiResp.Msg)\n\t}\n\t\n\t// 转换结果格式\n\tresults := p.convertResults(apiResp.List)\n\t\n\treturn results, nil\n}\n\n// convertResults 将API响应转换为标准SearchResult格式\nfunc (p *JikepanAsyncV2Plugin) convertResults(items []JikepanItem) []model.SearchResult {\n\tresults := make([]model.SearchResult, 0, len(items))\n\t\n\tfor i, item := range items {","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/jikepan/jikepan.go#L79-L115","documentation":"Wrapped decode error in jikepan's doSearch (plugin/jikepan/jikepan.go:97): the response body was read fully but json.Unmarshal against JikepanResponse failed, meaning the API returned content in an unexpected shape (HTML error page, changed schema) despite a successful request.","triggerScenarios":"json.Unmarshal(bodyBytes, &apiResp) fails: the API returned HTML (error page/anti-bot challenge), an empty body, or JSON whose types conflict with JikepanResponse fields.","commonSituations":"上游返回 HTML 拦截页；响应被代理改写。","solutions":["Log the HTTP status and first bytes of bodyBytes to see what was actually returned","Check resp.StatusCode before decoding; handle non-200 explicitly","Validate the site is reachable normally (anti-bot/Cloudflare interstitial)","Update JikepanResponse struct to match the current API schema"],"exampleFix":"// before\nif err := json.Unmarshal(bodyBytes, &apiResp); err != nil {\n\treturn nil, fmt.Errorf(\"decode response failed: %w\", err)\n}\n\n// after\nif resp.StatusCode != http.StatusOK {\n\treturn nil, fmt.Errorf(\"jikepan returned status %d: %s\", resp.StatusCode, truncate(bodyBytes, 200))\n}\nif err := json.Unmarshal(bodyBytes, &apiResp); err != nil {\n\treturn nil, fmt.Errorf(\"decode response failed (status %d): %w\", resp.StatusCode, err)\n}","handlingStrategy":"type-guard","validationCode":"if resp.StatusCode != http.StatusOK {\n\treturn fmt.Errorf(\"jikepan: unexpected status %d\", resp.StatusCode)\n}\nct := resp.Header.Get(\"Content-Type\")\nif !strings.Contains(ct, \"application/json\") {\n\treturn fmt.Errorf(\"jikepan: non-JSON content-type %q\", ct)\n}","typeGuard":"func looksLikeJSON(b []byte) bool {\n\tt := bytes.TrimSpace(b)\n\treturn len(t) > 0 && (t[0] == '{' || t[0] == '[')\n}","tryCatchPattern":"// Go\nresults, err := p.doSearch(ctx, keyword, ext)\nvar uerr *json.UnmarshalTypeError\nif errors.As(err, &uerr) {\n\tlog.Printf(\"jikepan schema drift at %v\", uerr.Field)\n}","preventionTips":["Check status code and Content-Type before decoding","Log a body snippet on decode failure","Keep JikepanResponse in sync with API docs","Use json.Decoder for streaming/disallow-unknown-fields control"],"tags":["json","http-response","decoding"],"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"}