{"record":{"id":"b099ae1d9d048448","repo":"spicetify/cli","slug":"invalid-utf-16le-data-length","errorCode":null,"errorMessage":"invalid UTF-16LE data length","messagePattern":"invalid UTF-16LE data length","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/utils/file-utils.go","lineNumber":76,"sourceCode":"\toriginalEndIdx := 2 + endIdx + len(stringContentBytes)\n\treturn string(decodedStringBytes), originalStartIdx, originalEndIdx, nil\n}\n\n// Helper function to encode a byte slice (assumed UTF-8) to UTF-16LE\nfunc encodeUTF16LE(data []byte) []byte {\n\tutf16Bytes := utf16.Encode([]rune(string(data)))\n\tbyteSlice := make([]byte, len(utf16Bytes)*2)\n\tfor i, r := range utf16Bytes {\n\t\tbinary.LittleEndian.PutUint16(byteSlice[i*2:], r)\n\t}\n\n\treturn byteSlice\n}\n\n// Helper function to decode a byte slice (UTF-16LE) to UTF-8\nfunc decodeUTF16LE(data []byte) ([]byte, error) {\n\tif len(data)%2 != 0 {\n\t\treturn nil, fmt.Errorf(\"invalid UTF-16LE data length\")\n\t}\n\n\tuint16s := make([]uint16, len(data)/2)\n\tfor i := 0; i < len(data)/2; i++ {\n\t\tuint16s[i] = binary.LittleEndian.Uint16(data[i*2:])\n\t}\n\n\trunes := utf16.Decode(uint16s)\n\treturn []byte(string(runes)), nil\n}\n","sourceCodeStart":58,"sourceCodeEnd":87,"githubUrl":"https://github.com/spicetify/cli/blob/1f13f736163165234eef4fb792a03f9b5b732aa4/src/utils/file-utils.go#L58-L87","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Check the length of the data region: it must be even (each UTF-16 code unit is 2 bytes) before decoding.","Verify the file is not truncated — compare its size against the expected full record and re-download/re-export if short.","Ensure start and end markers do not overlap and appear exactly once so the extracted slice boundaries are aligned.","If you own the data producer, guarantee even-length output; otherwise strip or repair the trailing odd byte before parsing."],"exampleFix":"// before\ndecoded, err := decodeUTF16LE(region)\n// after\nif len(region)%2 != 0 {\n\tregion = region[:len(region)-1] // or repair/re-fetch the source file\n}\ndecoded, err := decodeUTF16LE(region)","handlingStrategy":"validation","validationCode":"func validUTF16LE(data []byte) bool {\n\treturn data != nil && len(data)%2 == 0\n}","typeGuard":"// Go: guard on error text from the wrapped error\nfunc isInvalidUTF16Length(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"invalid UTF-16LE data length\")\n}","tryCatchPattern":"if err != nil {\n\tif isInvalidUTF16Length(err) {\n\t\t// treat as corrupt input; skip or repair\n\t\treturn \"\", ErrCorruptPrefs\n\t}\n\treturn err\n}","preventionTips":["Always assert len(data)%2 == 0 before decoding UTF-16 data you slice yourself.","Check file size parity (after the 2-byte BOM) as an integrity signal.","Avoid slicing regions whose boundaries depend on overlapping markers.","Detect truncation early: compare actual vs expected record size."],"tags":["go","utf16","encoding","validation"],"backgroundTag":"invalid-utf16-data-length","analyzedSha":"1f13f736163165234eef4fb792a03f9b5b732aa4","analyzedAt":"2026-08-31T18:57:59.754Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}