vitessio/vitess · error

invalid signature for Trie2: 0x%08x

Error message

invalid signature for Trie2: 0x%08x

What it means

UTrie2FromBytes rejects serialized Unicode Trie2 (UTrie2) data whose leading 4-byte signature/magic does not match the expected 'Tri2' (0x54726932) value. This guards the deserializer in go/mysql/icuregex/internal/utrie/utrie2.go against parsing random or corrupted bytes as a case-mapping trie. Big-endian ('2irT', 0x32697254) is recognized but explicitly unsupported and yields a different error.

Source

Thrown at go/mysql/icuregex/internal/utrie/utrie2.go:381

		/** Null index and data blocks, not shifted. */
		index2NullOffset, dataNullOffset uint16

		/**
		 * First code point of the single-value range ending with U+10ffff,
		 * rounded up and then shifted right by UTRIE2_SHIFT_1.
		 */
		shiftedHighStart uint16
	}

	var header utrie2Header
	header.signature = bytes.Uint32()

	switch header.signature {
	case 0x54726932:
	case 0x32697254:
		return nil, errors.New("unsupported: BigEndian encoding")
	default:
		return nil, fmt.Errorf("invalid signature for Trie2: 0x%08x", header.signature)
	}

	header.options = bytes.Uint16()
	header.indexLength = bytes.Uint16()
	header.shiftedDataLength = bytes.Uint16()
	header.index2NullOffset = bytes.Uint16()
	header.dataNullOffset = bytes.Uint16()
	header.shiftedHighStart = bytes.Uint16()

	var width int
	switch header.options & 0xf {
	case 0:
		width = 16
	case 1:
		width = 32
	default:
		return nil, errors.New("invalid width for serialized UTrie2")
	}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Verify the byte slice passed to UTrie2FromBytes starts exactly at the trie header with the 4-byte magic 0x54726932 ('Tri2' little-endian)
  2. Regenerate the ICU/trie data with the standard tooling so it is serialized little-endian, and re-embed it
  3. Check that any preceding header fields consumed by readData (options/lengths) were not skipped, shifting the read offset
  4. If the source data is big-endian (0x32697254), convert it to little-endian — the parser rejects big-endian outright

Example fix

// before: slicing from the start of the file
trie, err := utrie2.UTrie2FromBytes(blob)
// after: skip the file header to the trie data section
trie, err := utrie2.UTrie2FromBytes(blob[headerLen:])
Defensive patterns

Strategy: validation

Validate before calling

func validTrie2(b []byte) bool {
    return len(b) >= 4 && binary.LittleEndian.Uint32(b) == 0x54726932
}
if !validTrie2(data) { return errors.New("not a little-endian Trie2 blob") }

Type guard

func isTrie2Data(b []byte) bool {
    return len(b) >= 4 && string(b[0:4]) == "Tri2"
}

Prevention

When it happens

Trigger: Calling UTrie2FromBytes (via readData) with data whose first 4 bytes are not 0x54726932 — e.g. a truncated or corrupt embedded ICU data blob, wrong offset into the byte slice, a big-endian serialized trie, or passing entirely unrelated bytes.

Common situations: Regenerating or replacing ICU data files with a different tool/version that emits big-endian output; manual slicing of the data section at a wrong offset; corrupted binary blobs embedded in a build; porting data from another ICU distribution.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/0cf781fcea1d5381. Report an issue: GitHub.