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
- Set Protocol to match the server (Protocol: 3 only for RESP3-capable servers)
- Handle command-level errors (WRONGTYPE, NOGROUP) before treating the reply as data
- Confirm the key holds the expected type before issuing map-returning commands
- 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
- Only enable Protocol: 3 on RESP3-capable servers/proxies
- Check key TYPE before map-returning commands (HGETALL on non-hash)
- Handle cmd-level errors before data parsing
- Reset desynced connections instead of continuing reads
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
- redis: can't parse reply=%.100q reading string into buffer
- redis: can't parse reply=%.100q reading string
- redis: can't parse array/set/push reply: %.100q
- redis: got %d elements in the map, wanted %d
- redis: the length of the array must be a multiple of 2, got:
AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01).
Data as JSON: /api/errors/d9f8ab2121e0e330.
Report an issue: GitHub.