livekit/livekit · error
invalid number of bits, expected 0-64
Error message
invalid number of bits, expected 0-64
What it means
ReadBits returns this error when the requested bit count is outside the valid range [0, 64], since a single read can only populate a uint64. On range failure the reader is not advanced; on insufficient-data failure it enters the failure state and returns io.EOF.
Source
Thrown at pkg/sfu/rtpextension/dependencydescriptor/bitstreamreader.go:41
buf []byte
pos int
remainingBits int
}
func NewBitStreamReader(buf []byte) *BitStreamReader {
return &BitStreamReader{buf: buf, remainingBits: len(buf) * 8}
}
func (b *BitStreamReader) RemainingBits() int {
return b.remainingBits
}
// Reads `bits` from the bitstream. `bits` must be in range [0, 64].
// Returns an unsigned integer in range [0, 2^bits - 1].
// On failure sets `BitstreamReader` into the failure state and returns 0.
func (b *BitStreamReader) ReadBits(bits int) (uint64, error) {
if bits < 0 || bits > 64 {
return 0, errors.New("invalid number of bits, expected 0-64")
}
if b.remainingBits < bits {
b.remainingBits -= bits
return 0, io.EOF
}
remainingBitsInFirstByte := b.remainingBits % 8
b.remainingBits -= bits
if bits < remainingBitsInFirstByte {
// Reading fewer bits than what's left in the current byte, just
// return the portion of this byte that is needed.
offset := remainingBitsInFirstByte - bits
return uint64((b.buf[b.pos] >> offset) & ((1 << bits) - 1)), nil
}
var result uint64
if remainingBitsInFirstByte > 0 {
// Read all bits that were left in the current byte and consume that byte.View on GitHub (pinned to ee45c3f0b1)
Solutions
- Ensure ReadBits is only called with values 0-64
- Validate computed bit widths from parsed fields before passing them to ReadBits
- Abandon the whole parse when any bitstream error occurs (check err immediately after every read)
- Sanity-check the payload length before parsing
Example fix
// before
val, err := b.ReadBits(width) // width computed, may exceed 64
// after
if width < 0 || width > 64 {
return fmt.Errorf("invalid width %d", width)
}
val, err := b.ReadBits(width) Defensive patterns
Strategy: validation
Validate before calling
if bits >= 0 && bits <= 64 {
v, err := reader.ReadBits(bits)
} Try / catch
v, err := reader.ReadBits(bits)
if err != nil {
return nil // abort parse; do not reuse reader
} Prevention
- Abort the entire descriptor parse on the first bitstream error
- Clamp computed widths derived from untrusted fields before reading
- Fuzz-test the parser with random payloads
When it happens
Trigger: Calling BitStreamReader.ReadBits(bits) with bits < 0 or bits > 64, directly or via callers like Parse/readMandatoryFields when a corrupt descriptor produces a computed width out of range.
Common situations: Malformed or hostile DependencyDescriptor RTP payloads causing negative/oversized computed widths; bit misuse after a prior parse failure left the stream in a bad state.
Related errors
- invalid number of values, expected 0-2^31
- unknown job type
- invalid match expression result
- Could not parse keys, it needs to be exactly, "key: secret",
- participant identity cannot be empty
AI-assisted analysis of livekit/livekit@ee45c3f0b1 (2026-09-02).
Data as JSON: /api/errors/7d3d7df7830d6f18.
Report an issue: GitHub.