go-redis/redis · critical

redis: failed to create connection pool: %w

Error message

redis: failed to create connection pool: %w

What it means

Panicked from NewClient when newConnPool(opt, dialHook, name) returns an error. Pool creation failure is treated as fatal because the client cannot operate without a main pool; rather than returning a half-constructed client, NewClient panics so the caller fails fast.

Source

Thrown at redis.go:1954

	}
	c.init()

	// Initialize push notification processor using shared helper
	// 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))
	}

	// Optionally create a separate connection pool for pipelining, with its own
	// (typically larger) buffers, so pipelines can use big buffers without
	// bloating the main pool. Enabled when either pipeline buffer size is set.
	if opt.PipelineReadBufferSize > 0 || opt.PipelineWriteBufferSize > 0 {
		pipelineOpt := opt.clone()
		if opt.PipelineReadBufferSize > 0 {
			pipelineOpt.ReadBufferSize = opt.PipelineReadBufferSize
			// Same clamp Options.init applies to the main pool: RESP3 push
			// parsing needs a minimum read buffer, and a tiny pipeline reader
			// would break push-notification handling on pipeline conns.
			if pipelineOpt.Protocol == 3 && pipelineOpt.ReadBufferSize < proto.MinRESP3ReadBufferSize {
				pipelineOpt.ReadBufferSize = proto.MinRESP3ReadBufferSize

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Wrap redis.NewClient in a recover() to turn the panic into an error at the call site.
  2. Validate Options before construction: PoolSize > 0, MinIdleConns <= PoolSize, PoolTimeout > 0.
  3. Inspect the wrapped error (%w) for the specific pool-package rejection and fix the offending option.
  4. If the failure is environmental (e.g. a hook), remove or fix the custom dialer/pool hook.

Example fix

// before
client := redis.NewClient(opt) // panics on bad pool config

// after
defer func() {
    if r := recover(); r != nil {
        log.Fatalf("redis init failed: %v", r)
    }
}()
client := redis.NewClient(opt)
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate pool sizing before construction.
if opt.PoolSize <= 0 {
    return errors.New("PoolSize must be > 0")
}
if opt.MinIdleConns > opt.PoolSize {
    return errors.New("MinIdleConns cannot exceed PoolSize")
}

Try / catch

defer func() {
    if r := recover(); r != nil {
        return nil, fmt.Errorf("redis NewClient failed: %v", r)
    }
}()
return redis.NewClient(opt), nil

Prevention

When it happens

Trigger: redis.NewClient(opt) where the underlying pool constructor fails. Typically a misconfigured Options value causing pool initialization to error (invalid PoolSize <= 0, a bad pool hook, or an internal assertion in the pool package).

Common situations: PoolSize set to 0 or negative; MinIdleConns greater than PoolSize in a way the pool rejects; an internal pool/conn validation failing during construction; a programming error in a custom Dialer hook referenced during pool build.

Related errors


AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06). Data as JSON: /data/errors/e3c744172c63a954.json. Report an issue: GitHub.