-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Description
Simple:
newRdb.SubscribeHandler() reports "panic: nil pointer" after newRdb := redis.WithTimeout()
Because pubSubPool is not cloned
Sorry, English is not my native language, I wrote the details using AI.
Expected Behavior
A new Redis client instance created via WithTimeout() should retain the pubSubPool from the original client, allowing Pub/Sub operations (e.g., SubscribeHandler) to execute without memory errors.
Current Behavior
After calling WithTimeout() to clone a Redis client, using the new client for Pub/Sub operations triggers a nil pointer dereference panic. The error stack trace points to the pubSubPool field being nil in the cloned client:
panic: runtime error: invalid memory address or nil pointer dereference
go/pkg/mod/github.com/redis/go-redis/v9@v9.17.2/internal/pool/pubsub.go:37 +0x69
Root cause: The clone() method of baseClient does not copy the pubSubPool field to the new client instance.
Possible Solution
Modify the (c *baseClient) clone() *baseClient method in redis.go to explicitly clone the pubSubPool field from the original client to the new cloned instance.
Steps to Reproduce
- Initialize a base Redis client:
rdb := redis.NewClient(...) - Clone the client with a custom timeout:
newRdb := rdb.WithTimeout(time.Second) - Invoke Pub/Sub functionality on the cloned client:
newRdb.SubscribeHandler(ctx, channel, handler) - The program panics with the nil pointer dereference error mentioned above.
Context (Environment)
- Affected Version:
github.com/redis/go-redis/v9v9.17.2 - Problem Introduction: The issue emerged after the commit
https://github.com/redis/go-redis/commit/0ef6d0727d6a452b0ea6eeee6bef3a72d35495ba#diff-190fc9ceda3bbdbe723d493b8b99e2b9a0100c7d635bfe9b04246280bef6f67e - Impact: Breaks Pub/Sub functionality for clients cloned via
WithTimeout(), blocking related message subscription/publishing workflows.
Detailed Description
The baseClient struct in go-redis/v9 includes a pubSubPool field responsible for managing Pub/Sub connections. The WithTimeout() method relies on the clone() method to create a new client instance with updated timeout settings. However, the current implementation of clone() omits the pubSubPool field, leaving it as nil in the cloned client. When the cloned client attempts to perform Pub/Sub operations, it accesses the uninitialized pubSubPool, resulting in the nil pointer panic.
Possible Implementation
Update the clone() method of baseClient in redis.go to include the pubSubPool field during cloning:
func (c *baseClient) clone() *baseClient {
c.maintNotificationsManagerLock.RLock()
maintNotificationsManager := c.maintNotificationsManager
c.maintNotificationsManagerLock.RUnlock()
clone := &baseClient{
opt: c.opt,
connPool: c.connPool,
onClose: c.onClose,
pubSubPool: c.pubSubPool, // Add this line to clone pubSubPool
pushProcessor: c.pushProcessor,
maintNotificationsManager: maintNotificationsManager,
streamingCredentialsManager: c.streamingCredentialsManager,
}
return clone
}This change ensures the cloned client inherits the pubSubPool from the original client, eliminating the nil pointer dereference error.