fish2018/pansou · error
JSON解析失败
Error message
JSON解析失败: %w
What it means
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).
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).
Example fix
// before
if err := json.Unmarshal([]byte(jsonStr), &ashResults); err != nil {
return nil, fmt.Errorf("JSON解析失败: %w", err)
}
// after
if err := json.Unmarshal([]byte(jsonStr), &ashResults); err != nil {
return nil, fmt.Errorf("JSON解析失败(offset %q): %w", snippet(jsonStr, err), err)
} Defensive patterns
Strategy: validation
Validate before calling
if !json.Valid([]byte(jsonStr)) { return fmt.Errorf("extracted JSON invalid, head=%q", jsonStr[:200]) } Type guard
func isValidAshJSON(b []byte) bool { var v []AshResult; return json.Unmarshal(b, &v) == nil } Try / catch
var syn *json.SyntaxError
if errors.As(err, &syn) {
log.Printf("JSON syntax error at offset %d: %s", syn.Offset, jsonStr[max(0,syn.Offset-50):syn.Offset+50])
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/6f330dd61db57a07.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/ash/ash.go:145
// 查找JSON数据
matches := jsonDataRegex.FindStringSubmatch(html)
if len(matches) < 2 {
return []model.SearchResult{}, nil // 没有找到数据,返回空结果
}
// 提取JSON字符串
jsonStr := matches[1]
// 清理JSON字符串(批量操作,减少内存分配)
if strings.Contains(jsonStr, "\\/") {
jsonStr = strings.ReplaceAll(jsonStr, "\\/", "/")
}
jsonStr = controlCharRegex.ReplaceAllString(jsonStr, "")
// 解析JSON - 使用高性能的sonic库
var ashResults []AshResult
if err := json.Unmarshal([]byte(jsonStr), &ashResults); err != nil {
return nil, fmt.Errorf("JSON解析失败: %w", err)
}
// 如果没有结果,直接返回
if len(ashResults) == 0 {
return []model.SearchResult{}, nil
}
// 预分配切片容量,避免动态扩容
results := make([]model.SearchResult, 0, len(ashResults))
// 批量处理所有结果
for i := range ashResults {
item := &ashResults[i]
// 提前检查URL是否有效,避免无效处理
if item.URL == "" {
continue
}View on GitHub (pinned to beaa561337)