go-redis/redis · error
at least one channel is required
Error message
at least one channel is required
What it means
Ring.Subscribe panics with 'at least one channel is required' when called with zero channel arguments (ring.go:710-712). The Ring is client-side sharded, so the first channel name is used (via c.sharding.GetByKey(channels[0])) to pick the shard that owns the subscription; with no channels there is no key to route by, hence the guard. This is a programmer error and is enforced with a panic rather than an error return.
Source
Thrown at ring.go:711
s := shard.Client.connPool.Stats()
acc.Hits += s.Hits
acc.Misses += s.Misses
acc.Timeouts += s.Timeouts
acc.TotalConns += s.TotalConns
acc.IdleConns += s.IdleConns
}
return &acc
}
// Len returns the current number of shards in the ring.
func (c *Ring) Len() int {
return c.sharding.Len()
}
// Subscribe subscribes the client to the specified channels.
func (c *Ring) Subscribe(ctx context.Context, channels ...string) *PubSub {
if len(channels) == 0 {
panic("at least one channel is required")
}
shard, err := c.sharding.GetByKey(channels[0])
if err != nil {
// TODO: return PubSub with sticky error
panic(err)
}
return shard.Client.Subscribe(ctx, channels...)
}
// PSubscribe subscribes the client to the given patterns.
func (c *Ring) PSubscribe(ctx context.Context, channels ...string) *PubSub {
if len(channels) == 0 {
panic("at least one channel is required")
}
shard, err := c.sharding.GetByKey(channels[0])
if err != nil {View on GitHub (pinned to 36d97525cd)
Solutions
- Validate len(channels) > 0 before calling ring.Subscribe and skip/return an error when empty.
- Ensure your config/source for channel names always yields at least one entry, or guard the subscription step behind a feature/config check.
- Wrap Subscribe in a helper that returns an error on empty input instead of letting the Ring panic.
Example fix
// before
ring.Subscribe(ctx, channels...) // channels is empty -> panic
// after
if len(channels) == 0 {
return errors.New("no channels to subscribe")
}
sub := ring.Subscribe(ctx, channels...) Defensive patterns
Strategy: validation
Validate before calling
func subscribeRing(ctx context.Context, r *redis.Ring, channels []string) (*redis.PubSub, error) {
if len(channels) == 0 {
return nil, errors.New("at least one channel is required")
}
return r.Subscribe(ctx, channels...), nil
} Type guard
func nonEmptyChannels(channels []string) bool {
return len(channels) > 0
} Try / catch
defer func() {
if r := recover(); r != nil {
log.Printf("ring subscribe failed: %v", r)
}
}()
sub := r.Subscribe(ctx, channels...) Prevention
- Check len(channels) > 0 before calling Subscribe.
- Make config-driven channel lists default to at least one entry or skip the subscription step.
- Forward variadic args through a validating helper.
- Add tests that exercise the empty-input case explicitly.
When it happens
Trigger: Calling ring.Subscribe(ctx) with no variadic channel arguments; passing an empty []string slice; passing a slice that was built dynamically and ended up empty due to a filter/config miss.
Common situations: Dynamic channel lists sourced from config/env that came back empty; helper functions that forward a channels slice without checking length; tests that forgot to populate the channel list; conditional logic that subscribes only when a feature flag is set, but the Subscribe call still runs.
Related errors
- redis: SUBSCRIBE is not allowed on pooled connections when c
- redis: failed to create pubsub pool: %w
- redis: Watch requires at least one key
- redis: Watch requires at least one shard
- redis: JSON.SET mode must be NX or XX
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/52c9622b17d95c49.json.
Report an issue: GitHub.