{"record":{"id":"6f330dd61db57a07","repo":"fish2018/pansou","slug":"json-w","errorCode":null,"errorMessage":"JSON解析失败: %w","messagePattern":"JSON解析失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/ash/ash.go","lineNumber":145,"sourceCode":"\t// 查找JSON数据\n\tmatches := jsonDataRegex.FindStringSubmatch(html)\n\tif len(matches) < 2 {\n\t\treturn []model.SearchResult{}, nil // 没有找到数据，返回空结果\n\t}\n\t\n\t// 提取JSON字符串\n\tjsonStr := matches[1]\n\t\n\t// 清理JSON字符串（批量操作，减少内存分配）\n\tif strings.Contains(jsonStr, \"\\\\/\") {\n\t\tjsonStr = strings.ReplaceAll(jsonStr, \"\\\\/\", \"/\")\n\t}\n\tjsonStr = controlCharRegex.ReplaceAllString(jsonStr, \"\")\n\t\n\t// 解析JSON - 使用高性能的sonic库\n\tvar ashResults []AshResult\n\tif err := json.Unmarshal([]byte(jsonStr), &ashResults); err != nil {\n\t\treturn nil, fmt.Errorf(\"JSON解析失败: %w\", err)\n\t}\n\t\n\t// 如果没有结果，直接返回\n\tif len(ashResults) == 0 {\n\t\treturn []model.SearchResult{}, nil\n\t}\n\t\n\t// 预分配切片容量，避免动态扩容\n\tresults := make([]model.SearchResult, 0, len(ashResults))\n\t\n\t// 批量处理所有结果\n\tfor i := range ashResults {\n\t\titem := &ashResults[i]\n\t\t\n\t\t// 提前检查URL是否有效，避免无效处理\n\t\tif item.URL == \"\" {\n\t\t\tcontinue\n\t\t}","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/ash/ash.go#L127-L163","documentation":"Inside extractResultsFromBytes, after stripping control characters from the extracted JSON string, json.Unmarshal into []AshResult fails. The error is wrapped as 'JSON解析失败' so callers can see the exact decode position/syntax problem reported by encoding/json (or the underlying sonic decoder).","triggerScenarios":"The regex-extracted JSON string is truncated, contains invalid escapes/characters not removed by controlCharRegex, or has a different shape than []AshResult — ash.go:145.","commonSituations":"Extraction regex grabbed a partial JSON array (page format changed); site started double-escaping or embedding JSON inside JS expressions; content contains unescaped control characters the cleanup regex misses; sonic decoder stricter about some syntax.","solutions":["Log the first ~500 chars of jsonStr on failure to see the malformed region and the offset reported by the error.","Fix the extraction regex to capture the complete JSON blob (balance brackets or match to the correct terminator).","Extend controlCharRegex cleanup or use a JSON repair step for unescaped control characters.","Verify AshResult struct field types match the actual payload (e.g. numbers as json.Number to tolerate int/float drift)."],"exampleFix":"// before\nif err := json.Unmarshal([]byte(jsonStr), &ashResults); err != nil {\n    return nil, fmt.Errorf(\"JSON解析失败: %w\", err)\n}\n// after\nif err := json.Unmarshal([]byte(jsonStr), &ashResults); err != nil {\n    return nil, fmt.Errorf(\"JSON解析失败(offset %q): %w\", snippet(jsonStr, err), err)\n}","handlingStrategy":"validation","validationCode":"if !json.Valid([]byte(jsonStr)) { return fmt.Errorf(\"extracted JSON invalid, head=%q\", jsonStr[:200]) }","typeGuard":"func isValidAshJSON(b []byte) bool { var v []AshResult; return json.Unmarshal(b, &v) == nil }","tryCatchPattern":"var syn *json.SyntaxError\nif errors.As(err, &syn) {\n    log.Printf(\"JSON syntax error at offset %d: %s\", syn.Offset, jsonStr[max(0,syn.Offset-50):syn.Offset+50])\n}","preventionTips":["Sanitize control chars/escapes thoroughly before Unmarshal","Match AshResult field types to the real payload (use json.Number where ambiguous)","Ensure the extraction regex captures the full balanced JSON","Add fixture-based tests for the extractor"],"tags":["json","parsing","unmarshal","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"}