{"record":{"id":"53f3c62c437f8f1b","repo":"fish2018/pansou","slug":"w-53f3c6","errorCode":null,"errorMessage":"解析响应失败: %w","messagePattern":"解析响应失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/bixin/bixin.go","lineNumber":241,"sourceCode":"\t\t}\n\t\t\n\t\t// 状态码检查\n\t\tif resp.StatusCode != http.StatusOK {\n\t\t\tif i == p.retries {\n\t\t\t\treturn nil, false, fmt.Errorf(\"API返回非200状态码: %d\", resp.StatusCode)\n\t\t\t}\n\t\t\ttime.Sleep(500 * time.Millisecond)\n\t\t\tcontinue\n\t\t}\n\t\t\n\t\t// 请求成功，跳出重试循环\n\t\tbreak\n\t}\n\t\n\t// 解析响应\n\tvar apiResp BixinResponse\n\tif err := json.Unmarshal(responseBody, &apiResp); err != nil {\n\t\treturn nil, false, fmt.Errorf(\"解析响应失败: %w\", err)\n\t}\n\t\n\t// 处理结果\n\tresults := make([]model.SearchResult, 0, len(apiResp.Data))\n\tpostMap := make(map[string]BixinPost)\n\t\n\t// 创建帖子ID到帖子内容的映射\n\tfor _, post := range apiResp.Included {\n\t\tpostMap[post.ID] = post\n\t}\n\t\n\t// 遍历搜索结果\n\tfor _, discussion := range apiResp.Data {\n\t\t// 获取相关帖子\n\t\tpostID := discussion.Relationships.MostRelevantPost.Data.ID\n\t\tpost, ok := postMap[postID]\n\t\tif !ok {\n\t\t\tcontinue","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/bixin/bixin.go#L223-L259","documentation":"After a successful request, fetchPage unmarshals the response body into BixinResponse with json.Unmarshal; this error wraps any parse failure. It means the body is not valid JSON or its shape does not match BixinResponse (e.g. an HTML error page or a different field type). Unlike transport errors, no retry is attempted here.","triggerScenarios":"json.Unmarshal(responseBody, &apiResp) fails in fetchPage — response body is HTML (anti-bot page), empty, truncated, or JSON fields have types that don't match BixinResponse's struct tags.","commonSituations":"Site returns an HTML login/challenge page instead of JSON, API version changed its response schema, or a non-JSON error body slipped through because only status code was checked.","solutions":["Log a snippet of responseBody to see whether it's HTML, empty, or JSON with a different schema.","Add a content-type check (must be application/json) before unmarshalling.","Update the BixinResponse struct tags to match the current API schema.","Use json.Unmarshal with a generic map first to inspect the actual shape when debugging."],"exampleFix":"// before\nvar apiResp BixinResponse\nif err := json.Unmarshal(responseBody, &apiResp); err != nil {\n    return nil, false, fmt.Errorf(\"解析响应失败: %w\", err)\n}\n// after\nif !json.Valid(responseBody) {\n    return nil, false, fmt.Errorf(\"响应不是有效JSON: %q\", responseBody[:min(len(responseBody),200)])\n}\nvar apiResp BixinResponse\nif err := json.Unmarshal(responseBody, &apiResp); err != nil {\n    return nil, false, fmt.Errorf(\"解析响应失败: %w\", err)\n}","handlingStrategy":"validation","validationCode":"body, _ := io.ReadAll(resp.Body)\nif !json.Valid(body) {\n    return fmt.Errorf(\"响应不是有效JSON\")\n}\nif ct := resp.Header.Get(\"Content-Type\"); !strings.Contains(ct, \"application/json\") {\n    return fmt.Errorf(\"意外的Content-Type: %s\", ct)\n}","typeGuard":"func isValidBixinJSON(body []byte) bool {\n    var probe struct {\n        Data []json.RawMessage `json:\"data\"`\n    }\n    return json.Unmarshal(body, &probe) == nil\n}","tryCatchPattern":"results, err := plugin.Search(ctx, keyword)\nif err != nil {\n    var parseErr *json.SyntaxError\n    if errors.As(err, &parseErr) {\n        log.Printf(\"bixin返回了非JSON内容(偏移%d): %v\", parseErr.Offset, parseErr)\n    }\n}","preventionTips":["Validate Content-Type is application/json before unmarshalling","Keep struct tags in sync with the live API schema (add regression tests with fixture JSON)","Log raw response snippets when parsing fails","Handle HTML challenge pages explicitly instead of letting them reach the parser"],"tags":["json","parsing","response-schema","go"],"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"}