valyala/fasthttp · error

brotli: excessive input

Error message

brotli: excessive input

What it means

errBrotliExcessiveInput is returned by writeUnbrotli when a complete brotli stream is followed by bytes that are not part of it. The decoder stops consuming input once the stream terminates; if leftover bytes remain in the input buffer, fasthttp reports them as excessive input. The message matches what the previously used andybalholm/brotli decoder reported; fasthttp's own reader detects it.

Source

Thrown at brotli.go:201

	}
	if err == nil && r.excessiveInput() {
		return nn, errBrotliExcessiveInput
	}
	return nn, err
}

// AppendUnbrotliBytes appends unbrotlied src to dst and returns the resulting dst.
func AppendUnbrotliBytes(dst, src []byte) ([]byte, error) {
	w := &byteSliceWriter{b: dst}
	_, err := WriteUnbrotli(w, src)
	return w.b, err
}

// errBrotliExcessiveInput is returned when a complete brotli stream is followed
// by bytes that aren't part of it. github.com/andybalholm/brotli, the decoder
// fasthttp used before, reported this with the same message; go-brrr ignores
// the trailing bytes, so brotliSliceReader detects them instead.
var errBrotliExcessiveInput = errors.New("brotli: excessive input")

// brotliSliceReader hands the decoder everything but the final byte of b,
// releasing that byte only once the decoder asks for more input. A brotli
// stream is self-terminating and its final byte always carries stream bits, so
// a decoder that succeeds without asking for the held back byte ended before
// the end of b: the leftover is excessive input.
type brotliSliceReader struct {
	b []byte
}

func newBrotliSliceReader(b []byte) *brotliSliceReader {
	return &brotliSliceReader{b: b}
}

func (r *brotliSliceReader) Read(p []byte) (int, error) {
	if len(r.b) > 1 {
		// Always withhold the final byte.
		n := copy(p, r.b[:len(r.b)-1])

View on GitHub (pinned to c96f600972)

Solutions

  1. Validate the source of the compressed data: decompress exactly one stream and strip/ignore known trailing bytes at the producer side.
  2. If the extra bytes are benign (e.g. zero padding), slice the input to the exact stream length before decompressing or ignore the error deliberately.
  3. Compare bytes decompressed so far with the expected content length to find where the corruption originates.
  4. Re-fetch or re-request the body if it came from the network, since appended bytes usually indicate upstream corruption.

Example fix

// before
err := writeUnbrotli(dst, corruptedBody) // brotli: excessive input
// after
if err := writeUnbrotli(dst, body[:len(body)-paddingLen]); err != nil {
    return fmt.Errorf("brotli decode: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check: decompress and compare consumed bytes with expected content length
if expected := resp.Header.ContentLength(); expected > 0 && len(body) != expected {
    return fmt.Errorf("body length %d != content-length %d", len(body), expected)
}

Try / catch

var out bytes.Buffer
err := writeUnbrotli(&out, body)
if err != nil && err.Error() == "brotli: excessive input" {
    // tolerate known trailing padding
    log.Warn("trailing bytes after brotli stream ignored")
} else if err != nil {
    return err
}

Prevention

When it happens

Trigger: Calling writeUnbrotli (e.g. via Response/Request body decompression of Content-Encoding: br) on a body where valid brotli data is concatenated with trailing garbage, padding, or a second stream appended without framing.

Common situations: Proxies or caches that truncate/append to compressed bodies; concatenating two brotli-compressed chunks and decompressing as one stream; a corrupted upload where extra bytes were appended after compression.

Related errors


AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31). Data as JSON: /api/errors/4a635850914cbdd0. Report an issue: GitHub.