{"id":"e3c744172c63a954","repo":"go-redis/redis","slug":"redis-failed-to-create-connection-pool-w","errorCode":null,"errorMessage":"redis: failed to create connection pool: %w","messagePattern":"redis: failed to create connection pool: %w","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"redis.go","lineNumber":1954,"sourceCode":"\t}\n\tc.init()\n\n\t// Initialize push notification processor using shared helper\n\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","sourceCodeStart":1936,"sourceCodeEnd":1972,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/redis.go#L1936-L1972","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Wrap redis.NewClient in a recover() to turn the panic into an error at the call site.","Validate Options before construction: PoolSize > 0, MinIdleConns <= PoolSize, PoolTimeout > 0.","Inspect the wrapped error (%w) for the specific pool-package rejection and fix the offending option.","If the failure is environmental (e.g. a hook), remove or fix the custom dialer/pool hook."],"exampleFix":"// before\nclient := redis.NewClient(opt) // panics on bad pool config\n\n// after\ndefer func() {\n    if r := recover(); r != nil {\n        log.Fatalf(\"redis init failed: %v\", r)\n    }\n}()\nclient := redis.NewClient(opt)","handlingStrategy":"try-catch","validationCode":"// Validate pool sizing before construction.\nif opt.PoolSize <= 0 {\n    return errors.New(\"PoolSize must be > 0\")\n}\nif opt.MinIdleConns > opt.PoolSize {\n    return errors.New(\"MinIdleConns cannot exceed PoolSize\")\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        return nil, fmt.Errorf(\"redis NewClient failed: %v\", r)\n    }\n}()\nreturn redis.NewClient(opt), nil","preventionTips":["Always wrap redis.NewClient in recover() when config comes from external sources.","Add a config validator that checks all numeric Options fields have valid ranges.","Log the recovered panic with the wrapped error for fast root-cause analysis."],"tags":["pool","config","initialization","panic"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}