redis/go-redis · error
redis: can't read raw reply: %.100q
Error message
redis: can't read raw reply: %.100q
What it means
readRawReplyBuf copies the raw bytes of the next reply into a buffer; after failing to match any known RESP type byte on the first line it returns this error with the offending line. Raw-reply reads bypass normal typed parsing, so any unrecognizable type byte (or non-RESP garbage) triggers it.
Source
Thrown at internal/proto/reader.go:954
}
return buf, err
}
// Read the attribute key-value pairs. Iterate over pairs rather than
// n*2 elements so a count above MaxInt/2 can't overflow int to a
// negative loop bound and skip the body.
for i := 0; i < n; i++ {
for pair := 0; pair < 2; pair++ {
buf, err = r.readRawReplyBuf(buf)
if err != nil {
return buf, err
}
}
}
// Read the command reply that follows the attribute
return r.readRawReplyBuf(buf)
}
return buf, fmt.Errorf("redis: can't read raw reply: %.100q", line)
}
var crlf = []byte{'\r', '\n'}
// ReadRawReplyWriteTo streams the next RESP reply directly to w without intermediate allocations.
// Returns the number of bytes written and any error encountered.
func (r *Reader) ReadRawReplyWriteTo(w io.Writer) (int64, error) {
return r.readRawReplyWriteTo(w)
}
func (r *Reader) readRawReplyWriteTo(w io.Writer) (int64, error) {
line, err := r.readLine()
if err != nil {
return 0, err
}
var written int64
n, err := w.Write(line)View on GitHub (pinned to c5cad058c7)
Solutions
- Reset the connection after errors/timeouts to clear any desync before raw reads
- Log the %.100q payload to identify the unexpected first byte
- Ensure RESP3 protocol negotiation completed before reading raw replies (attribute handling depends on it)
- Verify the server/module actually emits standard RESP types
Defensive patterns
Strategy: type-guard
Validate before calling
// confirm RESP3 handshake before raw reads
if err := client.Do(ctx, "HELLO", "3").Err(); err != nil { /* server lacks RESP3 */ } Type guard
func isKnownRespType(b byte) bool {
switch b {
case '+', '-', ':', '$', '*', '_', '#', ',', '%', '~', '>', '=', '(', '!':
return true
}
return false
} Try / catch
buf, err := reader.ReadRawReply()
if err != nil && strings.Contains(err.Error(), "can't read raw reply") {
logger.Warn("unknown reply type on raw read; resetting conn", "err", err)
_ = conn.Close()
return err
} Prevention
- Complete RESP3 negotiation before raw reply capture
- Reset connections after any prior parse error
- Verify custom modules emit standard RESP types
- Inspect the logged %.100q line to identify unknown type bytes
When it happens
Trigger: ReadRawReply / readRawReplyBuf encountering a first line whose type byte is unknown — garbage after a desync, an unsupported RESP extension type, or non-Redis data on the stream; also after skipping RespAttr the following line still didn't parse.
Common situations: Raw reply capture features (e.g. debugging hooks or Do/Command raw paths) run against a desynced or proxied connection; custom server modules replying with non-standard types.
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: can't parse map 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/45814aaac5fa5921.
Report an issue: GitHub.