fish2018/pansou · warning

字符串以转义符结尾

Error message

字符串以转义符结尾

What it means

Error returned by decodeJSSingleQuotedString when the encoded string ends with a lone backslash: the escape character is the final byte with nothing following it to decode. In valid JavaScript string literals a backslash always escapes a following character, so a trailing backslash means the extracted literal is malformed — usually because the body was truncated after the marker or the scan/decode logic disagreed with the page's actual escaping.

Solutions

  1. Inspect the decoded string's tail and the matching page source to see how the site actually escapes trailing backslashes
  2. Make the decoder tolerant: treat a trailing lone backslash as a literal backslash instead of an error if the upstream really emits it
  3. Retry the request in case the page was truncated
  4. Add a round-trip unit test with a payload containing Windows paths to lock in the intended behavior

Example fix

// before
index++
if index >= len(encoded) {
    return nil, fmt.Errorf("字符串以转义符结尾")
}
// after
index++
if index >= len(encoded) {
    decoded = append(decoded, '\\') // tolerate trailing literal backslash
    return decoded, nil
}
Defensive patterns

Strategy: try-catch

Validate before calling

if len(encoded) > 0 && encoded[len(encoded)-1] == '\\' {
    return errors.New("payload ends with dangling escape — page likely truncated")
}

Type guard

func endsWithDanglingEscape(b []byte) bool {
    return len(b) > 0 && b[len(b)-1] == '\\'
}

Try / catch

if strings.Contains(err.Error(), "字符串以转义符结尾") {
    // retry the request (likely truncation) or degrade to empty results
}

Prevention

When it happens

Trigger: body ends with '\' right at the last byte of the scanned string: page truncated mid-literal, or scanSingleQuotedString terminated at a quote that the site itself escaped differently ('\\'' sequences edge cases), leaving a dangling escape.

Common situations: Upstream emits content containing trailing backslashes (e.g. Windows-style paths in titles) that the scanner decodes differently than the browser's JS engine; truncated CDN responses.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/23fe4800a00f6d8c. Report an issue: GitHub.

Appendix: source

Thrown at plugin/haitunsou/haitunsou.go:197

		case '\\':
			escaped = true
		case '\'':
			return body[start:index], nil
		}
	}
	return nil, fmt.Errorf("内嵌结果字符串未闭合")
}

func decodeJSSingleQuotedString(encoded []byte) ([]byte, error) {
	decoded := make([]byte, 0, len(encoded))
	for index := 0; index < len(encoded); index++ {
		if encoded[index] != '\\' {
			decoded = append(decoded, encoded[index])
			continue
		}
		index++
		if index >= len(encoded) {
			return nil, fmt.Errorf("字符串以转义符结尾")
		}
		switch encoded[index] {
		case '\\', '\'', '"', '/':
			decoded = append(decoded, encoded[index])
		case 'b':
			decoded = append(decoded, '\b')
		case 'f':
			decoded = append(decoded, '\f')
		case 'n':
			decoded = append(decoded, '\n')
		case 'r':
			decoded = append(decoded, '\r')
		case 't':
			decoded = append(decoded, '\t')
		case 'v':
			decoded = append(decoded, '\v')
		case '0':
			decoded = append(decoded, 0)

View on GitHub (pinned to beaa561337)