{"id":"8ad5d7edb9080b13","repo":"go-redis/redis","slug":"redis-failed-to-create-pubsub-pool-w","errorCode":null,"errorMessage":"redis: failed to create pubsub pool: %w","messagePattern":"redis: failed to create pubsub pool: %w","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"redis.go","lineNumber":1958,"sourceCode":"\t// Use void processor for RESP2 connections (push notifications not available)\n\tc.pushProcessor = initializePushProcessor(opt)\n\t// set opt push processor for child clients\n\tc.opt.PushNotificationProcessor = c.pushProcessor\n\n\t// Generate unique pool names for metrics\n\tuniqueID := generateUniqueID()\n\tmainPoolName := opt.Addr + \"_\" + uniqueID\n\tpubsubPoolName := opt.Addr + \"_\" + uniqueID + \"_pubsub\"\n\n\t// Create connection pools\n\tvar err error\n\tc.connPool, err = newConnPool(opt, c.dialHook, mainPoolName)\n\tif err != nil {\n\t\tpanic(fmt.Errorf(\"redis: failed to create connection pool: %w\", err))\n\t}\n\tc.pubSubPool, err = newPubSubPool(opt, c.dialHook, pubsubPoolName)\n\tif err != nil {\n\t\tpanic(fmt.Errorf(\"redis: failed to create pubsub pool: %w\", err))\n\t}\n\n\t// Optionally create a separate connection pool for pipelining, with its own\n\t// (typically larger) buffers, so pipelines can use big buffers without\n\t// bloating the main pool. Enabled when either pipeline buffer size is set.\n\tif opt.PipelineReadBufferSize > 0 || opt.PipelineWriteBufferSize > 0 {\n\t\tpipelineOpt := opt.clone()\n\t\tif opt.PipelineReadBufferSize > 0 {\n\t\t\tpipelineOpt.ReadBufferSize = opt.PipelineReadBufferSize\n\t\t\t// Same clamp Options.init applies to the main pool: RESP3 push\n\t\t\t// parsing needs a minimum read buffer, and a tiny pipeline reader\n\t\t\t// would break push-notification handling on pipeline conns.\n\t\t\tif pipelineOpt.Protocol == 3 && pipelineOpt.ReadBufferSize < proto.MinRESP3ReadBufferSize {\n\t\t\t\tpipelineOpt.ReadBufferSize = proto.MinRESP3ReadBufferSize\n\t\t\t}\n\t\t}\n\t\tif opt.PipelineWriteBufferSize > 0 {\n\t\t\tpipelineOpt.WriteBufferSize = opt.PipelineWriteBufferSize","sourceCodeStart":1940,"sourceCodeEnd":1976,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/redis.go#L1940-L1976","documentation":"Panicked from NewClient when newPubSubPool(opt, dialHook, name) returns an error after the main pool was already created. The pub/sub pool is dedicated to PubSub connections; failure here is fatal and the client panics rather than returning a structurally inconsistent client.","triggerScenarios":"redis.NewClient(opt) where the pubsub pool constructor fails. Same class as the main pool panic but for the pubsub-specific pool, which can be governed by different sizing options if customization is applied.","commonSituations":"Same shape as the main pool panic: invalid sizing, a bad hook, or an internal pool validation failure. Less common because the pubsub pool reuses the same opt, but a custom PubSub-specific configuration path or future option can trigger it.","solutions":["Wrap NewClient in recover() to surface the panic as an error.","Validate shared Options (PoolSize, PoolTimeout, MinIdleConns) before construction.","Inspect the wrapped error for the pubsub-pool-specific rejection.","If reproducible, bisect Options to find which field triggers the pool constructor error."],"exampleFix":"// before\nclient := redis.NewClient(opt)\n\n// after\nvar client *redis.Client\nfunc() {\n    defer func() {\n        if r := recover(); r != nil {\n            err, _ = r.(error)\n        }\n    }()\n    client = redis.NewClient(opt)\n}()","handlingStrategy":"try-catch","validationCode":"// Same pool sizing validation as the main pool applies to the pubsub pool.\nif opt.PoolSize <= 0 || opt.PoolTimeout <= 0 {\n    return errors.New(\"invalid pool options for pubsub pool\")\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        return nil, fmt.Errorf(\"redis NewClient (pubsub pool) failed: %v\", r)\n    }\n}()\nreturn redis.NewClient(opt), nil","preventionTips":["Wrap NewClient in recover() so a pubsub-pool panic does not crash the process.","Keep pool sizing options sane and shared across pools.","Bisect Options if a pubsub-pool panic appears after a config change."],"tags":["pool","pubsub","config","initialization","panic"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}