fish2018/pansou · warning
无效十六进制转义
Error message
无效十六进制转义: %w
What it means
decodeHexEscape calls strconv.ParseUint on the escaped hex digits; when those bytes are not valid hexadecimal, it wraps the parse error as 无效十六进制转义 (invalid hex escape). This indicates the plugin's JS string decoder encountered an escape like \xZZ or a slice containing non-hex characters.
Solutions
- Dump the failing slice (data[start:end]) to see what characters broke the parse
- Extend decodeHexEscape to handle the site's current escape syntax (e.g. \uXXXX, variable-length escapes)
- Check whether the page needs charset conversion (GBK/UTF-8) before decoding
- Skip items that fail to decode, using cleanText(rawTitle) as a fallback
Example fix
// before
value, err := strconv.ParseUint(string(data[start:end]), 16, 16)
if err != nil {
return 0, start, fmt.Errorf("无效十六进制转义: %w", err)
}
// after
value, err := strconv.ParseUint(string(data[start:end]), 16, 16)
if err != nil {
return 0, start, fmt.Errorf("无效十六进制转义 at %d (%q): %w", start, data[start:end], err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: verify all escape bytes are hex before decoding
for _, b := range data[start : start+length] {
if !isHexDigit(b) {
return string(data), nil // not a valid escape, use raw
}
} Type guard
func isHexDigit(b byte) bool {
return (b >= '0' && b <= '9') || (b >= 'a' && b <= 'f') || (b >= 'A' && b <= 'F')
} Try / catch
value, n, err := decodeHexEscape(data, i+2, 2)
if err != nil {
log.Printf("invalid hex escape at %d: %v", i, err)
return string(data), nil // keep raw title on decode failure
} Prevention
- Verify each escape byte is a hex digit before parsing
- Track upstream site changes to their JS obfuscation scheme
- Include the offending byte slice in error messages for faster diagnosis
When it happens
Trigger: decodeJSSingleQuotedString encounters a \x or multi-digit escape whose following bytes fail strconv.ParseUint(...,16,16): non-hex characters, or an empty/garbled slice passed as the escape.
Common situations: Upstream site changes obfuscation scheme (e.g. switches to \u{...} or raw Unicode), so bytes assumed to be hex digits are no longer valid; or page compression/decoding leaves stray bytes inside JS string literals.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/754ae0c9439e34a7.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/haitunsou/haitunsou.go:258
index = lowNext - 1
}
}
decoded = utf8.AppendRune(decoded, r)
default:
decoded = append(decoded, encoded[index])
}
}
return decoded, nil
}
func decodeHexEscape(data []byte, start, length int) (uint64, int, error) {
end := start + length
if start < 0 || end > len(data) {
return 0, start, fmt.Errorf("转义序列不完整")
}
value, err := strconv.ParseUint(string(data[start:end]), 16, 16)
if err != nil {
return 0, start, fmt.Errorf("无效十六进制转义: %w", err)
}
return value, end, nil
}
func convertItem(item searchItem) (model.SearchResult, bool) {
rawTitle := cleanText(item.Title)
if rawTitle == "" {
rawTitle = cleanText(item.Name)
}
if rawTitle == "" {
return model.SearchResult{}, false
}
title, description := splitTitleAndDescription(rawTitle)
if title == "" {
return model.SearchResult{}, false
}
linkType, normalizedURL, password := normalizeLink(item.URL, item.Code, item.IsType)View on GitHub (pinned to beaa561337)