fish2018/pansou · error

解析结果 JSON 失败

Error message

解析结果 JSON 失败: %w

What it means

Returned by parseEmbeddedList when jsonutil.Unmarshal fails to decode the extracted, escape-decoded string into []searchItem. The embedded string was found and scanned correctly, but its contents are not a JSON array matching the searchItem schema. Typically this means the site changed the data shape (array to object, added wrapper, renamed structure) or the JS-escape decoding produced corrupt bytes.

Solutions

  1. errors.Unwrap to see the json syntax/type error and byte offset, then fetch and inspect the decoded payload at that offset
  2. Update the searchItem struct's json tags/types to match the new upstream schema
  3. If the root became an object, adjust parseEmbeddedList to unwrap the results field before unmarshal
  4. Verify decodeJSSingleQuotedString output is valid UTF-8 (utf8.Valid) before unmarshaling

Example fix

// before
type searchItem struct {
    ID    int64  `json:"id"`
    URL   string `json:"url"`
}
// after — tolerate upstream sending id as string
var items []struct {
    ID    json.Number `json:"id"`
    URL   string      `json:"url"`
}
Defensive patterns

Strategy: try-catch

Validate before calling

decoded, err := decodeJSSingleQuotedString(encoded)
if err != nil { return err }
if !utf8.Valid(decoded) {
    return fmt.Errorf("decoded payload is not valid UTF-8")
}

Type guard

func looksLikeItemArray(b []byte) bool {
    var probe []map[string]json.RawMessage
    return json.Unmarshal(b, &probe) == nil
}

Try / catch

var jsonErr *json.UnmarshalTypeError
if errors.As(err, &jsonErr) {
    // schema drift at field jsonErr.Field: update searchItem tags
} else if errors.As(err, &syntaxErr) {
    // decoding bug or truncated payload
}

Prevention

When it happens

Trigger: The inline 'const list = JSON.parse('...' )' string unquotes to JSON that does not fit []searchItem: root is an object not an array, fields have different types (e.g. id became a string), or decodeJSSingleQuotedString mangled multi-byte content.

Common situations: Upstream schema evolution (is_type values change, url field renamed); decoder bug with unusual \x or surrogate-pair escapes; page contains a marker-like string in a comment with non-JSON content following it.

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/99536007aa16aa5c. Report an issue: GitHub.

Appendix: source

Thrown at plugin/haitunsou/haitunsou.go:162

			start = index + len(marker)
			break
		}
	}
	if start < 0 {
		return nil, fmt.Errorf("未找到页面内嵌结果")
	}

	encoded, err := scanSingleQuotedString(body, start)
	if err != nil {
		return nil, err
	}
	decoded, err := decodeJSSingleQuotedString(encoded)
	if err != nil {
		return nil, err
	}
	var items []searchItem
	if err := jsonutil.Unmarshal(decoded, &items); err != nil {
		return nil, fmt.Errorf("解析结果 JSON 失败: %w", err)
	}
	return items, nil
}

func indexBytes(data, marker []byte) int {
	return bytes.Index(data, marker)
}

func scanSingleQuotedString(body []byte, start int) ([]byte, error) {
	escaped := false
	for index := start; index < len(body); index++ {
		if escaped {
			escaped = false
			continue
		}
		switch body[index] {
		case '\\':
			escaped = true

View on GitHub (pinned to beaa561337)