redis/go-redis · error

redis: can't parse map reply: %.100q

Error message

redis: can't parse map reply: %.100q

What it means

ReadMapLen expected a RESP3 map type byte (%) or, as fallback, an RESP2 array byte, but the reply line starts with neither. The parser cannot interpret the reply as a map and reports the raw line truncated to 100 chars. This signals a reply type mismatch for map-expecting commands.

Source

Thrown at internal/proto/reader.go:770

	line, err := r.ReadLine()
	if err != nil {
		return 0, err
	}
	switch line[0] {
	case RespMap:
		return replyLen(line)
	case RespArray, RespSet, RespPush:
		// Some commands and RESP2 protocol may respond to array types.
		n, err := replyLen(line)
		if err != nil {
			return 0, err
		}
		if n%2 != 0 {
			return 0, fmt.Errorf("redis: the length of the array must be a multiple of 2, got: %d", n)
		}
		return n / 2, nil
	default:
		return 0, fmt.Errorf("redis: can't parse map reply: %.100q", line)
	}
}

// DiscardNext read and discard the data represented by the next line.
func (r *Reader) DiscardNext() error {
	line, err := r.readLine()
	if err != nil {
		return err
	}
	return r.Discard(line)
}

// Discard the data represented by line.
func (r *Reader) Discard(line []byte) (err error) {
	if len(line) == 0 {
		return errors.New("redis: invalid line")
	}
	switch line[0] {

View on GitHub (pinned to c5cad058c7)

Solutions

  1. Set Protocol to match the server (Protocol: 3 only for RESP3-capable servers)
  2. Handle command-level errors (WRONGTYPE, NOGROUP) before treating the reply as data
  3. Confirm the key holds the expected type before issuing map-returning commands
  4. Check for desync — reset pooled connections after errors or timeouts

Example fix

// before
opt := &redis.Options{Addr: addr, Protocol: 3}
// after: only request RESP3 when the server supports it
opt := &redis.Options{Addr: addr, Protocol: 3} // ensure server >= 6 / proxy supports RESP3
// or fall back:
opt := &redis.Options{Addr: addr} // RESP2 default
Defensive patterns

Strategy: type-guard

Validate before calling

// check server RESP capability before Protocol: 3
// HELLO 3 — if it errors, keep Protocol: 2

Type guard

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

Try / catch

n, err := reader.ReadMapLen()
if err != nil {
  if strings.Contains(err.Error(), "can't parse map reply") {
    // likely a server error reply or RESP2/3 mismatch
    return cmd.Err()
  }
  return err
}

Prevention

When it happens

Trigger: readReply, stringInterfaceMapParser (HGETALL-like), readStreamGroups, readXInfoStreamConsumers, readFunctions, readEngines encountering a scalar/error/nil reply where a map was expected — often a Redis error (e.g. WRONGTYPE, unknown command) surfacing at the wrong parse layer, or RESP2 server with Protocol: 3 configured.

Common situations: Forcing Protocol: 3 against a RESP2-only server or proxy; calling HGETALL on a non-hash key so WRONGTYPE arrives mid-parse; desync from earlier unconsumed replies.

Related errors


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