mudler/LocalAI · error

bytesToInt16sLE: input bytes slice has odd length, must be e

Error message

bytesToInt16sLE: input bytes slice has odd length, must be even

What it means

Panic in pkg/sound BytesToInt16sLE when the input byte slice has an odd number of bytes. The function reinterprets bytes as little-endian int16 pairs (two bytes per sample), so an odd length means half a sample — usually a truncated audio buffer — and rather than silently drop a byte it panics.

Source

Thrown at pkg/sound/int16.go:82

		// Linearly interpolate between the two surrounding input samples
		output[i] = int16((1-frac)*float64(input[indexBefore]) + frac*float64(input[indexAfter]))
	}

	return output
}

func ConvertInt16ToInt(input []int16) []int {
	output := make([]int, len(input)) // Allocate a slice for the output
	for i, value := range input {
		output[i] = int(value) // Convert each int16 to int and assign it to the output slice
	}
	return output // Return the converted slice
}

func BytesToInt16sLE(bytes []byte) []int16 {
	// Ensure the byte slice length is even
	if len(bytes)%2 != 0 {
		panic("bytesToInt16sLE: input bytes slice has odd length, must be even")
	}

	int16s := make([]int16, len(bytes)/2)
	for i := range len(int16s) {
		int16s[i] = int16(bytes[2*i]) | int16(bytes[2*i+1])<<8
	}
	return int16s
}

func Int16toBytesLE(arr []int16) []byte {
	le := binary.LittleEndian
	result := make([]byte, 0, 2*len(arr))
	for _, val := range arr {
		result = le.AppendUint16(result, uint16(val))
	}
	return result
}

View on GitHub (pinned to 44413a9d06)

Solutions

  1. Trim to even length before calling: process buf[:len(buf)-len(buf)%2] and carry the leftover byte into the next chunk
  2. For streams, buffer bytes and only convert when >=2 bytes are available, keeping the remainder
  3. Check upstream for truncation: verify the producer is sending whole PCM16 frames
  4. Use Int16toBytesLE / matching helpers on the producer side so lengths stay multiples of two

Example fix

// before
samples := sound.BytesToInt16sLE(chunk) // panics on odd chunk
// after
if odd := len(chunk) % 2; odd != 0 {
    chunk = chunk[:len(chunk)-1] // or stash last byte for next chunk
}
samples := sound.BytesToInt16sLE(chunk)
Defensive patterns

Strategy: validation

Validate before calling

func toInt16Safe(b []byte) ([]int16, []byte) {
    n := len(b) - len(b)%2
    return sound.BytesToInt16sLE(b[:n]), b[n:]
}

Type guard

func isEvenLength(b []byte) bool { return len(b)%2 == 0 }

Try / catch

// panics in Go; if the boundary is untrusted, wrap it
func safeBytesToInt16sLE(b []byte) (out []int16, err error) {
    defer func() { if r := recover(); r != nil { err = fmt.Errorf("odd byte length: %d", len(b)) } }()
    return sound.BytesToInt16sLE(b), nil
}

Prevention

When it happens

Trigger: Feeding PCM16 audio whose length is not a multiple of 2: a chunked stream split mid-sample, a buffer sliced with an off-by-one, or raw bytes from a source that includes a header/odd-sized footer concatenated with samples.

Common situations: Streaming TTS/ASR pipelines that chunk audio at arbitrary byte boundaries; mixing mono/stereo or headered formats (WAV headers stripped incorrectly); len(buf)-1 style slicing bugs; network reads returning partial frames.

Related errors


AI-assisted analysis of mudler/LocalAI@44413a9d06 (2026-08-15). Data as JSON: /api/errors/a106cdf79662a7c0. Report an issue: GitHub.