redis/go-redis · error
redis: Watch requires at least one key
Error message
redis: Watch requires at least one key
What it means
Ring.Watch (client-side sharding) rejects a WATCH invocation with no keys, since there would be no shard to run the transaction against. It returns a plain error rather than panicking.
Source
Thrown at ring.go:989
if err = hook(ctx, cmds); err != nil {
errs <- err
}
}(hash, cmds)
}
wg.Wait()
close(errs)
if err := <-errs; err != nil {
return err
}
return cmdsFirstErr(cmds)
}
func (c *Ring) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error {
if len(keys) == 0 {
return fmt.Errorf("redis: Watch requires at least one key")
}
var shards []*ringShard
for _, key := range keys {
if key != "" {
shard, err := c.sharding.GetByKey(key)
if err != nil {
return err
}
shards = append(shards, shard)
}
}
if len(shards) == 0 {
return fmt.Errorf("redis: Watch requires at least one shard")
}View on GitHub (pinned to c5cad058c7)
Solutions
- Guard before calling: return early or skip the transaction if len(keys) == 0
- Fix the upstream code that produces an empty key list
- If zero keys is legitimate, use the non-transactional API instead of Watch
Example fix
// before
ring.Watch(ctx, func(tx *redis.Tx) error { ... }, keys...) // keys empty
// after
if len(keys) == 0 {
return nil
}
return ring.Watch(ctx, func(tx *redis.Tx) error { ... }, keys...) Defensive patterns
Strategy: validation
Validate before calling
func watchKeys(keys ...string) ([]string, error) {
if len(keys) == 0 {
return nil, errors.New("Watch: no keys provided")
}
return keys, nil
} Try / catch
if err := ring.Watch(ctx, fn, keys...); err != nil {
if strings.Contains(err.Error(), "requires at least one key") {
return nil // treat as no-op
}
return err
} Prevention
- Guard len(keys) before building transactions
- Avoid passing variadic slices straight from dynamic sources
- Use the non-transactional API when no keys are involved
When it happens
Trigger: Calling ringClient.Watch(ctx, fn) with an empty keys variadic, e.g. passing a nil or empty keys slice at ring.go:989.
Common situations: Keys collected dynamically into a slice that ends up empty (cache-miss path, empty config); refactored code where keys were moved from literals to a variable.
Related errors
- redis: Watch requires at least one shard
- redis: Watch requires all keys to be in the same shard
- both LibName and LibVer cannot be set at the same time
- at least one of LibName and LibVer should be set
- redis: CLIENT TRACKING OPTIN and OPTOUT are mutually exclusi
AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01).
Data as JSON: /api/errors/1f78ff167342ab98.
Report an issue: GitHub.