grpc/grpc-go · critical

slice bounds out of range [%d:%d] with length 0

Error message

slice bounds out of range [%d:%d] with length 0

What it means

emptyBuffer (mem/buffers.go:260) is the zero-length Buffer returned by buffer.Slice when the requested range is empty (line 194-196). emptyBuffer.Slice (line 273-278) only permits Slice(0,0); any other indices panic with this custom out-of-range message because the buffer's length is 0. This mirrors Go's native slice-bounds panic but with an explicit, actionable message.

Source

Thrown at mem/buffers.go:275

	return buf.split(n)
}

type emptyBuffer struct{}

func (e emptyBuffer) ReadOnlyData() []byte {
	return nil
}

func (e emptyBuffer) Ref()  {}
func (e emptyBuffer) Free() {}

func (e emptyBuffer) Len() int {
	return 0
}

func (e emptyBuffer) Slice(start, end int) Buffer {
	if start != 0 || end != 0 {
		panic(fmt.Sprintf("slice bounds out of range [%d:%d] with length 0", start, end))
	}
	return e
}

func (e emptyBuffer) split(int) (left, right Buffer) {
	return e, e
}

func (e emptyBuffer) read([]byte) (int, Buffer) {
	return 0, e
}

// SliceBuffer is a Buffer implementation that wraps a byte slice. It provides
// methods for reading, splitting, and managing the byte slice.
type SliceBuffer []byte

// ReadOnlyData returns the byte slice.
func (s SliceBuffer) ReadOnlyData() []byte { return s }

View on GitHub (pinned to 0c51461d27)

Solutions

  1. Check Len() (or bounds) before slicing: only call Slice when start <= end <= Len().
  2. Handle the empty case explicitly (skip or return the empty buffer) rather than slicing blindly.
  3. Validate indices against the current buffer length, not a cached/stale length.

Example fix

// before
sub := buf.Slice(0, frameLen) // if buf is empty and frameLen>0 -> panic

// after
if buf.Len() == 0 {
    return buf // nothing to slice
}
sub := buf.Slice(0, min(frameLen, buf.Len()))
Defensive patterns

Strategy: validation

Validate before calling

// Bounds-check before slicing any buffer, especially empty ones.
func safeSliceAny(b mem.Buffer, start, end int) mem.Buffer {
    if end < start || start < 0 || end > b.Len() {
        return nil // or return b unchanged
    }
    return b.Slice(start, end)
}

Prevention

When it happens

Trigger: Obtaining an empty Buffer (Len()==0, e.g. from slicing a zero-length range or from Copy of empty data) and then calling Slice(start, end) where start != 0 or end != 0; computing slice indices without checking the buffer length first.

Common situations: Generic buffer-slicing code that assumes non-zero length; codecs that pre-slice fixed-size frames and hit a zero-length frame; tests that pass empty data through slicing helpers.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/a8a85a28af513fde. Report an issue: GitHub.