grpc/grpc-go · error
mem: allocating slice of size 2^%d is not possible
Error message
mem: allocating slice of size 2^%d is not possible
What it means
BinaryTieredBufferPool is constructed from power-of-two exponents; at buffer_pool.go:104 each exponent is bounds-checked against maxExponent = uintSize - 2 (62 on 64-bit, 30 on 32-bit platforms). Requesting a tier of size 2^exp where exp exceeds this limit is impossible to allocate as a Go slice on that architecture, so NewBinaryTieredBufferPool/NewDirtyBinaryTieredBufferPool returns an error instead of panicking. The exponent, not the byte count, is printed.
Source
Thrown at internal/mem/buffer_pool.go:105
func newBinaryTiered(sizedPoolFactory func(int) bufferPool, fallbackPool bufferPool, powerOfTwoExponents ...uint8) (*BinaryTieredBufferPool, error) {
slices.Sort(powerOfTwoExponents)
powerOfTwoExponents = slices.Compact(powerOfTwoExponents)
// Determine the maximum exponent we need to support. This depends on the
// word size (32-bit vs 64-bit).
maxExponent := uintSize - 2
indexOfNextLargestBit := slices.Repeat([]int{-1}, maxExponent+1)
indexOfPreviousLargestBit := slices.Repeat([]int{-1}, maxExponent+1)
maxTier := 0
pools := make([]bufferPool, 0, len(powerOfTwoExponents))
for i, exp := range powerOfTwoExponents {
// Allocating slices of size > 2^maxExponent isn't possible on
// maxExponent-bit machines.
if int(exp) > maxExponent {
return nil, fmt.Errorf("mem: allocating slice of size 2^%d is not possible", exp)
}
tierSize := 1 << exp
pools = append(pools, sizedPoolFactory(tierSize))
maxTier = max(maxTier, tierSize)
// Map the exact power of 2 to this pool index.
indexOfNextLargestBit[exp] = i
indexOfPreviousLargestBit[exp] = i
}
// Fill gaps for Get() (Next Largest)
// We iterate backwards. If current is empty, take the value from the right (larger).
for i := maxExponent - 1; i >= 0; i-- {
if indexOfNextLargestBit[i] == -1 {
indexOfNextLargestBit[i] = indexOfNextLargestBit[i+1]
}
}
View on GitHub (pinned to 0c51461d27)
Solutions
- Confirm you are passing exponents (log2 of the byte size), not raw byte sizes: pass 12 for 4 KiB, 14 for 16 KiB, 20 for 1 MiB.
- Clamp/validate the exponent against your platform's maxExponent: keep exponents <= 30 for 32-bit-safe code, <= 62 for 64-bit.
- If you genuinely need very large pooled buffers, fall back to a SimpleBufferPool/NopBufferPool that allocates on demand rather than a fixed tier.
- Unit-test pool construction with the exact exponents your config permits.
Example fix
// before: passing byte size as exponent // pool, err := mem.NewBinaryTieredBufferPool(4096, 16384) // // err: allocating slice of size 2^4096 is not possible // after: pass exponents // pool, err := mem.NewBinaryTieredBufferPool(12, 14) // 4 KiB, 16 KiB
Defensive patterns
Strategy: validation
Validate before calling
package main
import (
"fmt"
"math/bits"
)
// validExponent returns nil if exp can index a Go slice on this platform.
func validExponent(exp uint8) error {
maxExp := uint(bits.UintSize) - 2
if uint(exp) > maxExp {
return fmt.Errorf("exponent %d exceeds platform max %d", exp, maxExp)
}
return nil
}
// func main() {
// for _, e := range []uint8{12, 14, 20, 40} {
// if err := validExponent(e); err != nil { fmt.Println(err) }
// }
// } Try / catch
// Construction returns the error; check it explicitly.
//
// pool, err := mem.NewBinaryTieredBufferPool(12, 14, 20)
// if err != nil {
// return fmt.Errorf("buffer pool init: %w", err)
// } Prevention
- Always pass exponents (log2 byte size), never raw byte sizes.
- Keep exponents <= 30 if the binary may run on 32-bit platforms.
- Unit-test pool construction with the configured exponent set.
- Validate user/config-driven exponents before passing them to the constructor.
When it happens
Trigger: Triggered by NewBinaryTieredBufferPool(powerOfTwoExponents...) or NewDirtyBinaryTieredBufferPool(...) when one of the supplied uint8 exponents is greater than maxExponent (uintSize-2). For example passing 63 on a 64-bit build (2^63 bytes) or any value > 30 on a 32-bit build.
Common situations: A caller mistakenly passes the desired byte size (e.g. 4096, 16384) instead of the exponent (12, 14), or hard-codes an exponent that is valid on 64-bit but breaks 32-bit builds, or derives the exponent from attacker/config-controlled input without clamping.
Related errors
- unsupported mode: %v
- token file %q is empty: %w
- tokenFilePath cannot be empty
- local credentials rejected connection to non-local address %
- delegating_resolver: failed to determine proxy URL for targe
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/690a628d9508b64b.
Report an issue: GitHub.