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

  1. Log the first ~500 chars of jsonStr on failure to see the malformed region and the offset reported by the error.
  2. Fix the extraction regex to capture the complete JSON blob (balance brackets or match to the correct terminator).
  3. Extend controlCharRegex cleanup or use a JSON repair step for unescaped control characters.
  4. 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

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)