antonmedv/fx · error

Invalid Unicode escape sequence '\u%s'

Error message

Invalid Unicode escape sequence '\u%s'

What it means

In strict mode, scanString read 4 hex digits after \u but strconv.ParseInt failed — this occurs when the code point is a surrogate half used incorrectly... practically it fires when the hex string is out of the int32 range ParseInt(s,16,32) accepts (only possible with weird state) or, per the code path, when the parsed hex value cannot fit; the message shows the hex digits.

Source

Thrown at internal/jsonx/json.go:227

	p.next()
	escaped := false
	for {
		if escaped {
			escaped = false
			if p.strict {
				switch p.char {
				case 'u':
					var s string
					for i := 0; i < 4; i++ {
						p.next()
						if !utils.IsHexDigit(p.char) {
							panic(fmt.Sprintf("Invalid Unicode escape sequence '\\u%s%c'", s, p.char))
						}
						s += string(p.char)
					}
					_, err := strconv.ParseInt(s, 16, 32)
					if err != nil {
						panic(fmt.Sprintf("Invalid Unicode escape sequence '\\u%s'", s))
					}
				case '"', '\\', '/', 'b', 'f', 'n', 'r', 't':
				default:
					panic(fmt.Sprintf("Invalid escape sequence '\\%c'", p.char))
				}
			}
		} else if p.char == '\\' {
			escaped = true
		} else if p.char == '"' {
			break
		} else if p.char == 0 {
			panic("Unexpected end of input in string")
		} else if rune(p.char) > unicode.MaxRune {
			panic(fmt.Sprintf("Invalid character code point %d in string", p.char))
		}
		p.next()
	}

View on GitHub (pinned to 4f31cd3a0c)

Solutions

  1. Replace the raw \u escape with the literal UTF-8 character in the input
  2. Re-encode the document with encoding/json so all escapes are well-formed
  3. Decode surrogate pairs correctly (two \uXXXX halves) or use a single code point escape
  4. If the input is machine-generated, fix the generator to emit only valid \uXXXX (0000–FFFF) escapes

Example fix

// before
"\u{1F600}"  // invalid JS-style escape
// after
"\uD83D\uDE00"  // surrogate pair, or literal "😀"
Defensive patterns

Strategy: validation

Validate before calling

// Validate hex payload of \u escapes fits int32
for _, m := range unicodeEscapes.FindAllStringSubmatch(string(b), -1) {
	if _, err := strconv.ParseInt(m[1], 16, 32); err != nil {
		return fmt.Errorf("bad unicode escape %s", m[0])
	}
}

Try / catch

defer func() {
	if r := recover(); r != nil {
		if msg, ok := r.(string); ok && strings.Contains(msg, "Invalid Unicode escape") {
			err = fmt.Errorf("unparseable unicode escape: %s", msg)
		}
	}
}()

Prevention

When it happens

Trigger: Parse (strict) encountering '\u' + 4 hex chars that ParseInt(s, 16, 32) rejects; with 4 valid hex digits max value 0xFFFF this is rare, but the branch guards it and reports the full hex sequence.

Common situations: Generated or obfuscated JSON containing unusual \u sequences; tooling that emits escapes like \uFFFF+ beyond intent; also hit when investigating surrogate pairs '\uD83D\uDE00' if surrounding validation is strict.

Related errors


AI-assisted analysis of antonmedv/fx@4f31cd3a0c (2026-09-02). Data as JSON: /api/errors/a90a4b75e868ea9f. Report an issue: GitHub.