redis/go-redis · error
redis: can't parse reply=%.100q reading string into buffer
Error message
redis: can't parse reply=%.100q reading string into buffer
What it means
The reader received a reply line it could not interpret as a string when filling a caller-supplied buffer (ReadStringInto). After failing all known reply types (simple string, bulk string, verbatim, integer, etc.) it gives up and reports the raw line truncated to 100 chars. This almost always means the bytes on the wire are not a valid RESP reply for this position, or the reply type is one the parser does not support here.
Source
Thrown at internal/proto/reader.go:664
// Slow path: buffer is exactly large enough for the payload only, so
// read the payload into it and discard the CRLF separately.
if _, err := io.ReadFull(r.rd, buf[:n]); err != nil {
return 0, err
}
if _, err := r.rd.Discard(2); err != nil {
return 0, err
}
return n, nil
case RespInt, RespFloat:
s := line[1:]
if len(s) > len(buf) {
return 0, fmt.Errorf("redis: buffer too small: need %d bytes, have %d", len(s), len(buf))
}
return copy(buf, s), nil
}
return 0, fmt.Errorf("redis: can't parse reply=%.100q reading string into buffer", line)
}
func (r *Reader) ReadString() (string, error) {
line, err := r.ReadLine()
if err != nil {
return "", err
}
switch line[0] {
case RespStatus, RespInt, RespFloat:
return string(line[1:]), nil
case RespString:
return r.readStringReply(line)
case RespBool:
b, err := r.readBool(line)
return strconv.FormatBool(b), err
case RespVerbatim:
return r.readVerb(line)View on GitHub (pinned to c5cad058c7)
Solutions
- Ensure every issued command consumes exactly its reply — a desync from skipped replies makes subsequent reads parse garbage
- Verify the endpoint is a real Redis server and no proxy rewrites responses
- Use Protocol: 3 consistently if the server requires RESP3 types (maps/verbatim) your caller parses as strings
- Log the %.100q payload in the error to identify the unexpected type byte
Example fix
// before: reading a custom command reply as a fixed-size string buffer
cmd := NewStringCmd(ctx, "MYCMD")
reader.ReadStringInto(buf)
// after: parse according to the actual reply type
val, err := reader.ReadString()
if err != nil { return err }
copy(buf, val) Defensive patterns
Strategy: type-guard
Validate before calling
// ensure reply kind before reading into buffer
line, err := r.PeekReplyType() // or read via ReadString first
if err != nil { return err }
if len(buf) < neededLen { return ErrBufferTooSmall } Type guard
func isStringReply(t byte) bool {
return t == '+' || t == '$' || t == '=' || t == ':'
} Try / catch
n, err := reader.ReadStringInto(buf)
var perr *redis.ProtoError
if errors.As(err, &perr) {
// bad reply type or too-small buffer: log perr and reset connection
_ = conn.Close()
return fmt.Errorf("string-into parse failed: %w", err)
} Prevention
- Always buffer-length check before ReadStringInto (need >= reply size)
- Consume every reply of every command to keep the stream aligned
- Match Protocol setting to server capability
- Use redis-cli --raw to confirm reply shapes for custom commands
When it happens
Trigger: Calling ReadStringInto on a connection whose next reply is not a string-shaped RESP type (e.g. an array, map, nil, or unknown type byte), or when the line is corrupt/garbage from a protocol desync (e.g. after a partial read, a proxy injecting data, or talking to a non-Redis server).
Common situations: RESP proxies or load balancers mangling traffic; protocol desync after a previous command's reply was mis-consumed; pointing the client at a non-Redis service; RESP2 servers replying with types the caller didn't expect for custom commands.
Related errors
- redis: can't parse reply=%.100q reading string
- redis: can't parse array/set/push reply: %.100q
- redis: can't parse map reply: %.100q
- redis: can't read raw reply: %.100q
- redis: got %d elements in the array, wanted %d
AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01).
Data as JSON: /api/errors/9736d8835287dd23.
Report an issue: GitHub.