spicetify/cli · error
end marker not found after start index %d: %s
Error message
end marker not found after start index %d: %s
What it means
ReadStringFromUTF16Binary locates a delimited string inside a UTF-16LE file (e.g. Spotify prefs) by searching for an encoded start marker, then an encoded end marker after it. This error is returned when the start marker was found but bytes.Index never matches the UTF-16LE-encoded end marker in the remaining content. It wraps the end marker text in the message so the caller can see which delimiter was missing.
Source
Thrown at src/utils/file-utils.go:46
var searchStartMarker, searchEndMarker []byte
if !isUTF16LE {
return "", -1, -1, fmt.Errorf("file is not in UTF-16LE format: %s", inputFile)
}
contentToSearch = fileContent[2:]
searchStartMarker = encodeUTF16LE(startMarker)
searchEndMarker = encodeUTF16LE(endMarker)
startIdx = bytes.Index(contentToSearch, searchStartMarker)
if startIdx == -1 {
return "", -1, -1, fmt.Errorf("start marker not found: %s", string(startMarker))
}
searchSpace := contentToSearch[startIdx+len(searchStartMarker):]
endIdx = bytes.Index(searchSpace, searchEndMarker)
if endIdx == -1 {
return "", -1, -1, fmt.Errorf("end marker not found after start index %d: %s", startIdx+len(searchStartMarker), string(endMarker))
}
stringContentBytes := contentToSearch[startIdx : startIdx+len(searchStartMarker)+endIdx+len(searchEndMarker)]
decodedStringBytes, err := decodeUTF16LE(stringContentBytes)
if err != nil {
return "", -1, -1, fmt.Errorf("error decoding UTF-16LE content: %w", err)
}
// Adjust indices to be byte offsets in the original file
originalStartIdx := 2 + startIdx
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)))View on GitHub (pinned to 1f13f73616)
Solutions
- Verify the end marker string matches exactly what the producing application writes (including case and spacing) and re-run.
- Open the file in a UTF-16LE-aware hex/text editor and confirm the closing marker bytes actually exist after the start marker.
- Check the reported start index in the error message and inspect bytes from there onward to see what text actually follows.
- Regenerate or re-export the file if it is truncated/corrupt, then retry the parse.
Example fix
// before: marker literal guess
s, a, b, err := utils.ReadStringFromUTF16Binary(prefs, []byte("<name>"), []byte("</Value>"))
// after: marker verified against the actual file content
s, a, b, err := utils.ReadStringFromUTF16Binary(prefs, []byte("<name>"), []byte("</name>"))
if err != nil {
log.Fatalf("parse prefs: %v", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: check the file exists and is plausibly UTF-16LE before calling
if fi, err := os.Stat(inputFile); err != nil || fi.Size() < 4 {
return fmt.Errorf("prefs file missing or too small")
} Type guard
// Go has no runtime type guards; use an explicit error sentinel check
func isEndMarkerNotFound(err error) bool {
return err != nil && strings.Contains(err.Error(), "end marker not found")
} Try / catch
val, _, _, err := utils.ReadStringFromUTF16Binary(prefs, start, end)
if err != nil {
if strings.Contains(err.Error(), "end marker not found") {
// fall back to defaults or re-export the file
return defaultVal, nil
}
return fmt.Errorf("parse prefs: %w", err)
} Prevention
- Copy marker strings directly from the real file's bytes instead of retyping them.
- Log the reported start index and hex-dump the following bytes when debugging marker mismatches.
- Handle file truncation: verify file size/parity before parsing UTF-16 content.
- Wrap this parser in a helper that maps marker errors to a clear domain error.
When it happens
Trigger: Calling ReadStringFromUTF16Binary(inputFile, startMarker, endMarker) where the file contains the startMarker (UTF-16LE encoded) but no endMarker after it — e.g. a typo'd end marker, a marker in a different case/format than the file's encoding, or a truncated/corrupt file that lost the closing section.
Common situations: Parsing an older or newer version of the file whose delimiter strings changed; passing an ASCII end marker while the file stores UTF-16 (handled internally, but a wrong literal still fails); the file was cut off mid-write so the closing tag is absent; marker text differs by whitespace or capitalization from what the app wrote.
Related errors
- error decoding UTF-16LE content: %w
- invalid UTF-16LE data length
- error reading file %s: %w
- file is not in UTF-16LE format: %s
- start marker not found: %s
AI-assisted analysis of spicetify/cli@1f13f73616 (2026-08-31).
Data as JSON: /api/errors/efc1b6c2d65b170a.
Report an issue: GitHub.