redis/go-redis · critical

redis: failed to create pubsub pool: %w

Error message

redis: failed to create pubsub pool: %w

What it means

Raised when constructing the dedicated PubSub connection pool during client creation fails. Like the main pool, failure means an invalid pool configuration rather than a network problem. NewClient panics because the client would be unusable without its pubsub pool.

Source

Thrown at redis.go:2120

	// Use void processor for RESP2 connections (push notifications not available)
	c.pushProcessor = initializePushProcessor(opt)
	// set opt push processor for child clients
	c.opt.PushNotificationProcessor = c.pushProcessor

	// Generate unique pool names for metrics
	uniqueID := generateUniqueID()
	mainPoolName := opt.Addr + "_" + uniqueID
	pubsubPoolName := opt.Addr + "_" + uniqueID + "_pubsub"

	// Create connection pools
	var err error
	c.connPool, err = newConnPool(opt, c.dialHook, mainPoolName)
	if err != nil {
		panic(fmt.Errorf("redis: failed to create connection pool: %w", err))
	}
	c.pubSubPool, err = newPubSubPool(opt, c.dialHook, pubsubPoolName)
	if err != nil {
		panic(fmt.Errorf("redis: failed to create pubsub pool: %w", err))
	}

	// Create the dedicated pipeline pool unconditionally, like pubSubPool: it
	// is pure burst capacity (no pre-dialing, small cap, larger buffers — see
	// pipelinePoolOptions), so an unused pipeline pool holds zero connections
	// and costs nothing. Pipelines stop competing with regular commands for
	// main-pool connections; a burst wider than the pool's cap spills back to
	// the main pool (see withPipelineConn). PipelinePoolSize < 0 opts out.
	if opt.PipelinePoolSize >= 0 {
		ref, err := c.buildPipelinePool(opt.Addr + "_" + uniqueID + "_pipeline")
		if err != nil {
			panic(fmt.Errorf("redis: failed to create pipeline connection pool: %w", err))
		}
		c.pipelinePool = ref
	}

	if opt.StreamingCredentialsProvider != nil {
		c.streamingCredentialsManager = streaming.NewManager(c.connPool, c.opt.PoolTimeout)

View on GitHub (pinned to c5cad058c7)

Solutions

  1. Inspect the wrapped inner error to identify the bad option
  2. Correct the invalid redis.Options field used for the pubsub pool
  3. If pubsub is unused, still fix Options — the pool is created unconditionally

Example fix

// before
redis.NewClient(&redis.Options{Addr: addr, ReadBufferSize: -1})
// after
redis.NewClient(&redis.Options{Addr: addr}) // let the library use defaults
Defensive patterns

Strategy: validation

Validate before calling

if opt.ReadBufferSize < 0 || opt.WriteBufferSize < 0 { return errors.New("buffer sizes must be non-negative") }
client := redis.NewClient(opt)

Try / catch

defer func() {
    if r := recover(); r != nil {
        err = fmt.Errorf("redis client init failed: %v", r)
    }
}()

Prevention

When it happens

Trigger: redis.NewClient with Options that make newPubSubPool fail (invalid pool sizing/buffer options affecting the pubsub pool), at redis.go:2120.

Common situations: The same invalid Options that break the main pool usually hit here right after error 200 — e.g. invalid ReadBufferSize/WriteBufferSize or negative size fields; building Options from unvalidated config files.

Related errors


AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01). Data as JSON: /api/errors/e51461df34c9d844. Report an issue: GitHub.