redis/go-redis · error

redis: can't parse array/set/push reply: %.100q

Error message

redis: can't parse array/set/push reply: %.100q

What it means

ReadArrayLen expected the next reply to be an array, set, or push type (RESP type bytes *, ~, >) but got something else. The parser cannot return a length for a non-aggregate reply, so it fails with the raw line for diagnosis. In RESP2 mode maps are also accepted via the array fallback, so this error means the reply is fundamentally not an aggregate.

Source

Thrown at internal/proto/reader.go:731

		return err
	}
	if n != fixedLen {
		return fmt.Errorf("redis: got %d elements in the array, wanted %d", n, fixedLen)
	}
	return nil
}

// ReadArrayLen Read and return the length of the array.
func (r *Reader) ReadArrayLen() (int, error) {
	line, err := r.ReadLine()
	if err != nil {
		return 0, err
	}
	switch line[0] {
	case RespArray, RespSet, RespPush:
		return replyLen(line)
	default:
		return 0, fmt.Errorf("redis: can't parse array/set/push reply: %.100q", line)
	}
}

// ReadFixedMapLen reads fixed map length.
func (r *Reader) ReadFixedMapLen(fixedLen int) error {
	n, err := r.ReadMapLen()
	if err != nil {
		return err
	}
	if n != fixedLen {
		return fmt.Errorf("redis: got %d elements in the map, wanted %d", n, fixedLen)
	}
	return nil
}

// ReadMapLen reads the length of the map type.
// If responding to the array type (RespArray/RespSet/RespPush),
// it must be a multiple of 2 and return n/2.

View on GitHub (pinned to c5cad058c7)

Solutions

  1. Check the redis error actually returned (NOGROUP, WRONGTYPE, etc.) — handle command-level errors before parsing
  2. Set Protocol: 3 if server replies use RESP3 sets/pushes your parser expects as aggregates
  3. Verify each command's reply is fully consumed to avoid stream desync
  4. Run the command with redis-cli --raw to see the actual reply type

Example fix

// before: blindly parsing next reply as array
n, err := reader.ReadArrayLen()
// after: check cmd error first
if err := cmd.Err(); err != nil { return err }
n, err := reader.ReadArrayLen()
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure the key/command can return an aggregate
// e.g. TYPE mykey == list/stream before XINFO/XRANGE-style reads

Type guard

func isArrayLikeReply(t byte) bool {
  return t == '*' || t == '~' || t == '>' || t == '%'
}

Try / catch

n, err := reader.ReadArrayLen()
if err != nil {
  if strings.Contains(err.Error(), "can't parse array/set/push") {
    // server returned an error or scalar; surface cmd error to caller
    return cmd.Err()
  }
  return err
}

Prevention

When it happens

Trigger: readReply or stream/xinfo parsers (readXMessageSlice, readXMessage, readStreamGroups, readXInfoStream*) encountering a scalar, error, or nil reply where an array was expected — e.g. an error reply (like NOSCRIPT or NOGROUP) reaching the array parser due to desync, or a nil bulk reply.

Common situations: Calling XREADGROUP with an invalid group so the error surfaces mid-parse; RESP2/RESP3 protocol mismatch changing reply types; connection reuse after a partially consumed reply.

Related errors


AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01). Data as JSON: /api/errors/cba44b0a4458bf1f. Report an issue: GitHub.