{"record":{"id":"379fde99e7c647be","repo":"fish2018/pansou","slug":"s-json-w-379fde","errorCode":null,"errorMessage":"[%s] JSON解析失败: %w","messagePattern":"\\[(.+?)\\] JSON解析失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/xys/xys.go","lineNumber":280,"sourceCode":"\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 != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求HTTP状态错误: %d\", p.Name(), resp.StatusCode)\n\t}\n\n\t// 读取响应体\n\trespBody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 读取响应体失败: %w\", p.Name(), err)\n\t}\n\n\t// 解析JSON响应\n\tvar searchResp SearchResponse\n\tif err := json.Unmarshal(respBody, &searchResp); err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] JSON解析失败: %w\", p.Name(), err)\n\t}\n\n\tif searchResp.Code != 0 {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索API返回错误: %s\", p.Name(), searchResp.Msg)\n\t}\n\n\tif p.debugMode {\n\t\tlog.Printf(\"[XYS] 搜索API响应成功，data长度: %d\", len(searchResp.Data))\n\t}\n\n\t// 解析HTML内容\n\treturn p.parseSearchResults(searchResp.Data, keyword)\n}\n\n// parseSearchResults 解析搜索结果HTML\nfunc (p *XysPlugin) parseSearchResults(htmlData, keyword string) ([]model.SearchResult, error) {\n\tdoc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlData))\n\tif err != nil {","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/xys/xys.go#L262-L298","documentation":"The XYS plugin's executeSearch received the HTTP response body but json.Unmarshal failed to parse it into SearchResponse. This means the response body is not valid JSON (or JSON that doesn't match SearchResponse's shape, e.g. an array instead of an object). The plugin wraps the parse error with the plugin name and %w so the underlying Go error is preserved.","triggerScenarios":"A GET to the XYS search endpoint returned a body that json.Unmarshal rejects: HTML error pages, Cloudflare/WAF interstitials, empty bodies, gzip/charset garbage, or a JSON top-level array when SearchResponse expects an object.","commonSituations":"Upstream site is temporarily down or behind an anti-bot page; reverse proxy (nginx) returns an HTML 502 page; the API changed its response envelope after a site update; a misconfigured proxy injects its own error page.","solutions":["Log the raw respBody (or its first few hundred bytes) to see what the server actually returned.","Check the HTTP status code before unmarshalling; handle non-200 responses separately instead of attempting to parse HTML as JSON.","Retry after a delay — anti-bot/CDN pages are often transient.","Update the plugin if the XYS API response schema changed."],"exampleFix":"// before\nvar searchResp SearchResponse\nif err := json.Unmarshal(respBody, &searchResp); err != nil {\n    return nil, fmt.Errorf(\"[%s] JSON解析失败: %w\", p.Name(), err)\n}\n// after\nif resp.StatusCode != http.StatusOK {\n    return nil, fmt.Errorf(\"[%s] 搜索API返回非200状态: %d, body: %.200s\", p.Name(), resp.StatusCode, string(respBody))\n}\nvar searchResp SearchResponse\nif err := json.Unmarshal(respBody, &searchResp); err != nil {\n    return nil, fmt.Errorf(\"[%s] JSON解析失败: %w, body: %.200s\", p.Name(), err, string(respBody))\n}","handlingStrategy":"try-catch","validationCode":"// Go: validate before trusting the parse\nif resp.StatusCode != http.StatusOK {\n    return fmt.Errorf(\"unexpected status %d\", resp.StatusCode)\n}\nif !json.Valid(respBody) {\n    return fmt.Errorf(\"response body is not valid JSON\")\n}","typeGuard":null,"tryCatchPattern":"results, err := search(keyword)\nif err != nil {\n    if strings.Contains(err.Error(), \"JSON解析失败\") {\n        log.Printf(\"XYS returned non-JSON body; retrying later: %v\", err)\n        return fallbackResults\n    }\n    return err\n}","preventionTips":["Check HTTP status codes before unmarshalling response bodies.","Log truncated raw bodies on parse failure for diagnosis.","Keep the plugin updated against upstream API changes.","Use a proxy/UA config that avoids anti-bot HTML pages."],"tags":["json","http","unmarshal","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"}