spicetify/cli · error

invalid UTF-16LE data length

Error message

invalid UTF-16LE data length

What it means

decodeUTF16LE converts a UTF-16LE byte slice to UTF-8 by reinterpreting every 2 bytes as one uint16 code unit. It returns "invalid UTF-16LE data length" when the input length is odd, because a truncated final code unit cannot be decoded. It is internal, so callers see it wrapped as "error decoding UTF-16LE content" from ReadStringFromUTF16Binary.

Source

Thrown at src/utils/file-utils.go:76

	originalEndIdx := 2 + endIdx + len(stringContentBytes)
	return string(decodedStringBytes), originalStartIdx, originalEndIdx, nil
}

// Helper function to encode a byte slice (assumed UTF-8) to UTF-16LE
func encodeUTF16LE(data []byte) []byte {
	utf16Bytes := utf16.Encode([]rune(string(data)))
	byteSlice := make([]byte, len(utf16Bytes)*2)
	for i, r := range utf16Bytes {
		binary.LittleEndian.PutUint16(byteSlice[i*2:], r)
	}

	return byteSlice
}

// Helper function to decode a byte slice (UTF-16LE) to UTF-8
func decodeUTF16LE(data []byte) ([]byte, error) {
	if len(data)%2 != 0 {
		return nil, fmt.Errorf("invalid UTF-16LE data length")
	}

	uint16s := make([]uint16, len(data)/2)
	for i := 0; i < len(data)/2; i++ {
		uint16s[i] = binary.LittleEndian.Uint16(data[i*2:])
	}

	runes := utf16.Decode(uint16s)
	return []byte(string(runes)), nil
}

View on GitHub (pinned to 1f13f73616)

Solutions

  1. Check the length of the data region: it must be even (each UTF-16 code unit is 2 bytes) before decoding.
  2. Verify the file is not truncated — compare its size against the expected full record and re-download/re-export if short.
  3. Ensure start and end markers do not overlap and appear exactly once so the extracted slice boundaries are aligned.
  4. If you own the data producer, guarantee even-length output; otherwise strip or repair the trailing odd byte before parsing.

Example fix

// before
decoded, err := decodeUTF16LE(region)
// after
if len(region)%2 != 0 {
	region = region[:len(region)-1] // or repair/re-fetch the source file
}
decoded, err := decodeUTF16LE(region)
Defensive patterns

Strategy: validation

Validate before calling

func validUTF16LE(data []byte) bool {
	return data != nil && len(data)%2 == 0
}

Type guard

// Go: guard on error text from the wrapped error
func isInvalidUTF16Length(err error) bool {
	return err != nil && strings.Contains(err.Error(), "invalid UTF-16LE data length")
}

Try / catch

if err != nil {
	if isInvalidUTF16Length(err) {
		// treat as corrupt input; skip or repair
		return "", ErrCorruptPrefs
	}
	return err
}

Prevention

When it happens

Trigger: Any code path where a byte slice with len(data)%2 != 0 reaches decodeUTF16LE — in practice, when the marker-delimited region extracted by ReadStringFromUTF16Binary contains an odd number of bytes (truncation, overlapping markers, or stray bytes inside the region).

Common situations: Truncated downloads or files cut off mid-record; a region slice off by one because start/end markers overlap; binary corruption from editing a UTF-16 file with an ASCII editor; concatenating files with an extra stray byte.

Understand the failure class

Related errors


AI-assisted analysis of spicetify/cli@1f13f73616 (2026-08-31). Data as JSON: /api/errors/b099ae1d9d048448. Report an issue: GitHub.