go-redis/redis · error
redis: SUBSCRIBE is not allowed on pooled connections when c
Error message
redis: SUBSCRIBE is not allowed on pooled connections when client-side caching is enabled
What it means
Returned when a raw SUBSCRIBE/UNSUBSCRIBE/PSUBSCRIBE is sent over an ordinary pooled connection on a CSC-enabled client. Client-side caching requires the pooled connection to stay in RESP3 tracking mode, but raw subscriptions put it into subscribe mode and break that contract. The typed pubsub methods (client.Subscribe) use a dedicated PubSub connection and remain allowed.
Source
Thrown at csc_integration.go:543
// errAuthWithCSC rejects runtime authentication because it can change one
// connection's ACL identity without changing the client's fixed cache namespace.
var errAuthWithCSC = errors.New(
"redis: AUTH is not allowed when client-side caching is enabled")
// errHelloWithCSC rejects HELLO with arguments because it can switch a tracked
// connection out of RESP3 (and can also change authentication).
var errHelloWithCSC = errors.New(
"redis: HELLO with arguments is not allowed when client-side caching is enabled")
// errResetWithCSC rejects RESET because it disables tracking and switches the
// connection to RESP2.
var errResetWithCSC = errors.New(
"redis: RESET is not allowed when client-side caching is enabled")
// errSubscribeWithCSC rejects raw subscriptions on the ordinary pool. The
// typed Subscribe methods use dedicated PubSub connections and remain allowed.
var errSubscribeWithCSC = errors.New(
"redis: SUBSCRIBE is not allowed on pooled connections when client-side caching is enabled")
// cscCommandError rejects commands that can make a pooled connection's state
// diverge from the assumptions used by CSC.
func (c *baseClient) cscCommandError(cmd Cmder) error {
// The successful attachment signal is shared with derived clients.
// initConn's internal command wrapper is exempt during library setup.
if !c.cscTrackingRequested() || c.allowClientTracking {
return nil
}
switch {
case isClientTrackingCmd(cmd):
return errClientTrackingWithCSC
case isSelectCmd(cmd):
return errSelectWithCSC
case isAuthCmd(cmd):
return errAuthWithCSC
case isProtocolChangingHelloCmd(cmd):View on GitHub (pinned to 36d97525cd)
Solutions
- Use the typed pubsub API: pubsub := client.Subscribe(ctx, "channel").
- If raw subscribe is mandatory, disable built-in CSC (leave Options.ClientSideCache nil).
Example fix
// before client.Do(ctx, "SUBSCRIBE", "events") // after pubsub := client.Subscribe(ctx, "events") msg, err := pubsub.ReceiveMessage(ctx)
Defensive patterns
Strategy: validation
Validate before calling
// Always use the typed pubsub API instead of raw SUBSCRIBE.
o := client.Options()
if o.ClientSideCache != nil || o.ClientSideCacheConfig != nil {
pubsub := client.Subscribe(ctx, "channel")
_ = pubsub
} else {
client.Do(ctx, "SUBSCRIBE", "channel")
} Type guard
func canRawSubscribe(c *redis.Client) bool {
o := c.Options()
return o.ClientSideCache == nil && o.ClientSideCacheConfig == nil
} Try / catch
err := client.Do(ctx, "SUBSCRIBE", "ch").Err()
if err != nil && strings.Contains(err.Error(), "SUBSCRIBE is not allowed") {
pubsub := client.Subscribe(ctx, "ch")
_ = pubsub.ReceiveMessage(ctx)
} Prevention
- Never use Do("SUBSCRIBE") — always client.Subscribe/Subscribe.
- Treat CSC-enabled clients as tracking-only pooled connections.
When it happens
Trigger: Calling client.Do(ctx, "SUBSCRIBE", "channel") on a client with Options.ClientSideCache set. The cscCommandError guard fires via isSubscribeCmd for any subscribe-family command sent through the normal process path.
Common situations: Mixing a hand-rolled subscribe loop with a CSC-enabled client, or copy-pasting subscribe code that uses Do() instead of the typed API.
Related errors
- redis: RESET is not allowed when client-side caching is enab
- at least one channel is required
- failed to create Pub/Sub messages metric: %w
- redis: failed to create pubsub pool: %w
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/b672ae3e333e53ea.json.
Report an issue: GitHub.