go-redis/redis · error

redis: got %d elements in cluster info, expected at least 2

Error message

redis: got %d elements in cluster info, expected at least 2

What it means

Thrown by ClusterSlotsCmd.readReply while parsing the CLUSTER SLOTS reply (command.go:4688). Each slot-range entry is a RESP array whose first two elements are the start/end slot; if an entry has fewer than 2 elements the parser cannot read the slot range and aborts rather than desync the RESP stream. Note the message text says 'cluster info' but this is actually the CLUSTER SLOTS parser.

Source

Thrown at command.go:4688

func (cmd *ClusterSlotsCmd) String() string {
	cmd.await()
	return cmdString(cmd, cmd.val)
}

func (cmd *ClusterSlotsCmd) readReply(rd *proto.Reader) error {
	n, err := rd.ReadArrayLen()
	if err != nil {
		return err
	}
	cmd.val = make([]ClusterSlot, n)

	for i := 0; i < len(cmd.val); i++ {
		n, err = rd.ReadArrayLen()
		if err != nil {
			return err
		}
		if n < 2 {
			return fmt.Errorf("redis: got %d elements in cluster info, expected at least 2", n)
		}

		start, err := rd.ReadInt()
		if err != nil {
			return err
		}

		end, err := rd.ReadInt()
		if err != nil {
			return err
		}

		// subtract start and end.
		nodes := make([]ClusterNode, n-2)

		for j := 0; j < len(nodes); j++ {
			nn, err := rd.ReadArrayLen()
			if err != nil {

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Verify the endpoint is a real Redis Cluster node: run `redis-cli -h <host> -p <port> CLUSTER SLOTS` and confirm each entry is [start, end, [ip, port, ...], ...].
  2. If a proxy/Redis-compatible service is in the path, point directly at a cluster node or switch to the standalone redis.Client.
  3. Upgrade go-redis; newer versions are more tolerant and prefer CLUSTER SHARDS on Redis >= 7.
  4. If the error is transient (during failover), retry after the cluster topology settles.

Example fix

// before: client is a ClusterClient pointed at a proxy
slots, err := client.ClusterSlots(ctx).Result()
// after: connect directly to a real cluster node
// client = redis.NewClusterClient(&redis.ClusterOptions{Addrs: []string{"real-node:6379"}})
slots, err := client.ClusterSlots(ctx).Result()
Defensive patterns

Strategy: validation

Validate before calling

// Before relying on ClusterSlots, confirm the endpoint is a real cluster node.
info, err := client.ClusterInfo(ctx).Result()
if err != nil || !strings.Contains(info, "cluster_enabled:1") {
    return fmt.Errorf("not a redis cluster endpoint; cannot use ClusterSlots")
}

Try / catch

slots, err := client.ClusterSlots(ctx).Result()
if err != nil {
    // log and degrade: reload topology, or fall back to standalone client
    _ = client.ReloadState(ctx)
    return err
}

Prevention

When it happens

Trigger: Calling client.ClusterSlots(ctx).Result() against a server whose CLUSTER SLOTS output contains a malformed/truncated slot entry: a Redis-compatible proxy mangling the reply, a Redis fork with a non-standard shape, a split/corrupted frame mid-failover, or pointing a ClusterClient at a standalone/non-cluster node.

Common situations: Pointing ClusterClient at Twemproxy/Envoy/a RESP-rewriting proxy, or at a Redis-compatible service (some KeyDB/Dragonfly/Valkey builds, managed proxies in front of Redis Enterprise) whose CLUSTER SLOTS layout differs. Also seen transiently during resharding/failover when a reply is split across reads.

Related errors


AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06). Data as JSON: /data/errors/099827230aa99f25.json. Report an issue: GitHub.