grpc/grpc-go · critical
Failed to create default buffer pool: %v
Error message
Failed to create default buffer pool: %v
What it means
The mem package init() (mem/buffer_pool.go:52-57) builds the process-wide default BufferPool from the hardcoded defaultBufferPoolSizeExponents ([8,12,14,15,20]) via NewBinaryTieredBufferPool. If that constructor returns an error (invalid, duplicate, or out-of-range power-of-two exponents, or an empty list), init panics because the package cannot operate without a pool. This is a startup-time, fail-fast guard.
Source
Thrown at mem/buffer_pool.go:56
Put(*[]byte)
}
var (
defaultBufferPoolSizeExponents = []uint8{
8,
12, // Go page size, 4KB
14, // 16KB (max HTTP/2 frame size used by gRPC)
15, // 32KB (default buffer size for io.Copy)
20, // 1MB
}
defaultBufferPool BufferPool
)
func init() {
var err error
defaultBufferPool, err = NewBinaryTieredBufferPool(defaultBufferPoolSizeExponents...)
if err != nil {
panic(fmt.Sprintf("Failed to create default buffer pool: %v", err))
}
internal.SetDefaultBufferPool = func(pool BufferPool) {
defaultBufferPool = pool
}
internal.SetBufferPoolingThresholdForTesting = func(threshold int) {
bufferPoolingThreshold = threshold
}
}
// DefaultBufferPool returns the current default buffer pool. It is a BufferPool
// created with NewBufferPool that uses a set of default sizes optimized for
// expected workflows.
func DefaultBufferPool() BufferPool {
return defaultBufferPool
}
View on GitHub (pinned to 0c51461d27)
Solutions
- Use an unmodified, released grpc-go; remove any go.mod `replace google.golang.org/grpc => ...` that points to a fork.
- If you forked mem and changed defaultBufferPoolSizeExponents, keep them distinct, non-empty, and within the valid power-of-two exponent range.
- Construct your own pool with mem.NewBinaryTieredBufferPool and inspect its error; do not rely on overriding the package default in production (internal.SetDefaultBufferPool is for tests).
Example fix
// Not caller code; this is the library's own init.
// If you forked mem/buffer_pool.go and broke the defaults, restore them:
// var defaultBufferPoolSizeExponents = []uint8{8, 12, 14, 15, 20}
//
// If you need a custom pool in your app, build it explicitly and pass it via
// dial/server options; do NOT edit the package-level default. Defensive patterns
Strategy: validation
Validate before calling
// The panic is in mem.init(); callers cannot intercept it. Validate your own
// pool construction explicitly instead of relying on overrides:
func buildPool(exps ...uint8) (mem.BufferPool, error) {
return mem.NewBinaryTieredBufferPool(exps...)
}
// Usage:
// p, err := buildPool(8, 12, 14, 15, 20)
// if err != nil { log.Fatal(err) } Prevention
- Use unmodified, released grpc-go; remove go.mod `replace` directives that point to forks.
- If you fork mem, keep defaultBufferPoolSizeExponents distinct and within the valid exponent range.
- Build and inspect your own pool with NewBinaryTieredBufferPool rather than editing the package default.
When it happens
Trigger: Not triggerable by normal callers with stock grpc-go. Fires only if the internal exponent list becomes invalid (library regression), if the underlying internal/mem.NewBinaryTieredBufferPool validation rules change, or if a fork edits defaultBufferPoolSizeExponents to bad values (e.g. duplicates like [8,8] or values >30).
Common situations: Forking/patching the mem package and editing defaultBufferPoolSizeExponents; a go.mod `replace` directive pointing grpc-go to a broken fork or commit; using a corrupted or in-development build where the internal constructor's validation rejects the defaults.
Related errors
- cannot register a nil CodecV2
- Cannot read freed buffer
- Cannot ref freed buffer
- Cannot free freed buffer
- Cannot slice freed buffer
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/48feb2e2799c7b3f.
Report an issue: GitHub.