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

  1. Ensure ReadBits is only called with values 0-64
  2. Validate computed bit widths from parsed fields before passing them to ReadBits
  3. Abandon the whole parse when any bitstream error occurs (check err immediately after every read)
  4. 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

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


AI-assisted analysis of livekit/livekit@ee45c3f0b1 (2026-09-02). Data as JSON: /api/errors/7d3d7df7830d6f18. Report an issue: GitHub.