kovidgoyal/kitty · error

output slice too small: need at least

Error message

output slice too small: need at least %d, got %d

What it means

StreamingBase64Decoder.Decode is an iterator (iter.Seq2) that writes decoded bytes into a caller-provided output slice. It precomputes maxPossibleOutput = NeededOutputLen(len(input)) (accounting for leftover buffered input bytes) and immediately yields this error if the output slice is smaller, without decoding anything.

Solutions

  1. Always size the buffer via s.NeededOutputLen(len(chunk)) before each call.
  2. Allocate generously: make([]byte, base64.StdEncoding.DecodedLen(len(input))+8).
  3. Check the first yielded error and grow the buffer, then retry the same chunk.
  4. Read the API doc comment: the output must be at least NeededOutputLen().

Example fix

// before
out := make([]byte, len(chunk)*3/4)
for decoded, err := range dec.Decode(chunk, out) { ... }
// after
out := make([]byte, dec.NeededOutputLen(len(chunk)))
for decoded, err := range dec.Decode(chunk, out) { ... }
Defensive patterns

Strategy: validation

Validate before calling

out := make([]byte, dec.NeededOutputLen(len(chunk)))
for b, err := range dec.Decode(chunk, out) { ... }

Try / catch

for b, err := range dec.Decode(chunk, out) {
    if err != nil && strings.Contains(err.Error(), "too small") {
        out = make([]byte, dec.NeededOutputLen(len(chunk)))
        // retry same chunk
    }
}

Prevention

When it happens

Trigger: Calling Decode with an output buffer sized only for the current chunk while leftover bytes from a previous call exist, or any buffer smaller than 3*ceil(totalInput/4). E.g. passing make([]byte, len(input)/4*3) when 2 bytes were buffered from before.

Common situations: Callers reusing a fixed-size chunk buffer across streaming iterations and forgetting the decoder carries state; off-by-one sizing that ignores base64 padding semantics.

Related errors


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/7030281644b70f4b. Report an issue: GitHub.

Appendix: source

Thrown at tools/utils/streaming_base64/api.go:41

		return CorruptInputError(int64(e) + chunkOffset)
	}
	return err
}

// The size of output buffer needed for the provided size of input
func (s *StreamingBase64Decoder) NeededOutputLen(input_len int) int {
	return ((input_len + s.num_leftover) / 4) * 3
}

// Decode provided input, iterating in chunks. Each chunk is a slice from the
// provided output buffer, which must be at least s.NeededOutputLen() in size.
func (s *StreamingBase64Decoder) Decode(input []byte, output []byte) iter.Seq2[[]byte, error] {
	// Base64 decoding: 4 input bytes -> 3 output bytes.
	// We check if output is large enough for this chunk + any buffered data.
	maxPossibleOutput := s.NeededOutputLen(len(input))
	return func(yield func([]byte, error) bool) {
		if len(output) < maxPossibleOutput {
			yield(nil, fmt.Errorf("output slice too small: need at least %d, got %d", maxPossibleOutput, len(output)))
			return
		}
		currIn := input
		outOffset := 0

		// 1. Handle leftover bytes from previous call
		if s.num_leftover > 0 {
			need := 4 - s.num_leftover
			if len(currIn) >= need {
				copy(s.leftover[s.num_leftover:], currIn[:need])

				// Decode the bridge block
				n, err := base64.StdEncoding.Decode(output[outOffset:], s.leftover[:4])
				if err != nil {
					yield(nil, wrap_error(err, s.total_read-int64(s.num_leftover)))
					return
				}

View on GitHub (pinned to 6d5d0c4406)