go-redis/redis · error
redis: invalid line
Error message
redis: invalid line
What it means
Returned by the RESP reader's Discard when it receives a zero-length line (reader.go:785-786). A well-formed RESP stream never has a bare empty line, so this signals protocol desynchronization — the reader and server have lost framing alignment, typically due to a corrupted stream, a man-in-the-middle/proxy mangling bytes, or reading past a closed connection.
Source
Thrown at internal/proto/reader.go:786
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] {
case RespStatus, RespError, RespInt, RespNil, RespFloat, RespBool, RespBigInt:
return nil
}
n, err := replyLen(line)
if err != nil {
if err == Nil {
// A nil reply ($-1, =-1, !-1, *-1, %-1) carries no payload; the
// header line was already consumed by readLine, so there is
// nothing to discard. Falling through would Discard(n+2)==2 bytes
// that belong to the next reply and desync the stream, matching
// how readRawReplyBuf/readRawReplyWriteTo already treat Nil.
return nil
}
return err
}View on GitHub (pinned to 36d97525cd)
Solutions
- The connection is unusable after desync — let the pool close it and retry on a fresh connection.
- Verify you are talking to a real Redis (not a proxy that rewrites RESP), and that TLS/non-TLS matches.
- Check for network-level corruption or MTU/fragmentation issues.
Example fix
// the error implies the conn is desynced — drop it and retry
for i := 0; i < 3; i++ {
err := client.Get(ctx, key).Err()
if err == nil { break }
if strings.Contains(err.Error(), "invalid line") { continue }
} Defensive patterns
Strategy: retry
Validate before calling
// Cannot pre-validate a live stream. Ensure endpoint is real Redis and // protocol/TLS matches the server.
Try / catch
for i := 0; i < 3; i++ {
err := client.Get(ctx, key).Err()
if err == nil { break }
if strings.Contains(err.Error(), "invalid line") {
// desync — let the pool discard this conn and retry
continue
}
return err
} Prevention
- Connect directly to Redis; avoid RESP-rewriting proxies.
- Match TLS settings to the server (rediss:// vs redis://).
- Monitor for network corruption and MTU issues.
When it happens
Trigger: Discard(line) called with an empty byte slice during response parsing, e.g. after a partial read, a truncated reply, or a misbehaving proxy that injects/strip bytes. Often surfaces during DiscardNext/Discard of multi-bulk replies.
Common situations: A L7 proxy or RESP-mangling sidecar, TLS corruption, half-closed sockets, or a non-Redis endpoint answering on the Redis port.
Related errors
- redis: all ring shards are down
- redis: all sentinels specified in configuration are unreacha
- failed to subscribe to streaming credentials: %w
- failed to initialize connection options: %w
- redis: expected '*', but got line %q
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/67c808b19fbfc2b7.json.
Report an issue: GitHub.