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

  1. Use an unmodified, released grpc-go; remove any go.mod `replace google.golang.org/grpc => ...` that points to a fork.
  2. If you forked mem and changed defaultBufferPoolSizeExponents, keep them distinct, non-empty, and within the valid power-of-two exponent range.
  3. 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

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


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