redis/go-redis · error

redis: can't parse verbatim string reply: %q

Error message

redis: can't parse verbatim string reply: %q

What it means

This error is thrown when go-redis receives a RESP3 verbatim string reply (the '=' reply type, e.g. from LODEN/? commands like INFO with verbatim output) whose payload does not have the required 4-byte type prefix ('txt:' or 'mkd:') followed by the actual content. The protocol expects the first 3 characters to be a format identifier and the 4th character to be a colon. If the payload is shorter than 4 bytes or byte 3 is not ':', the reply is malformed for the verbatim-string contract and the library refuses to guess the format.

Source

Thrown at internal/proto/reader.go:421

		return "", err
	}

	b := make([]byte, n+2)
	_, err = io.ReadFull(r.rd, b)
	if err != nil {
		return "", err
	}

	return util.BytesToString(b[:n]), nil
}

func (r *Reader) readVerb(line []byte) (string, error) {
	s, err := r.readStringReply(line)
	if err != nil {
		return "", err
	}
	if len(s) < 4 || s[3] != ':' {
		return "", fmt.Errorf("redis: can't parse verbatim string reply: %q", line)
	}
	return s[4:], nil
}

func (r *Reader) readSlice(line []byte) ([]interface{}, error) {
	n, err := replyLen(line)
	if err != nil {
		return nil, err
	}

	val := make([]interface{}, n)
	for i := 0; i < len(val); i++ {
		v, err := r.ReadReply()
		if err != nil {
			if err == Nil {
				val[i] = nil
				continue
			}

View on GitHub (pinned to c5cad058c7)

Solutions

  1. Check what command produced the reply; ensure the target actually supports that command and RESP3 verbatim strings (run with Protocol: 3 only against servers that support RESP3).
  2. Remove or bypass any RESP-rewriting proxy between the client and the Redis server, or upgrade it to a version that forwards '=' replies with the type prefix intact.
  3. If you control the server/module emitting the reply, make it prefix verbatim payloads with 'txt:' (or another valid 3-char format + ':').
  4. As a workaround, switch the connection to Protocol: 2 so the reply is delivered as a plain bulk string instead of a verbatim string, or parse the raw reply yourself via a custom hook.

Example fix

// before: forcing RESP3 against a proxy that mangles verbatim replies
opts := &redis.Options{Addr: "proxy:6379", Protocol: 3}
// after: use RESP2 so verbatim '=' replies arrive as plain bulk strings
opts := &redis.Options{Addr: "proxy:6379", Protocol: 2}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check: only issue verbatim-returning commands against servers confirmed to
// support RESP3 verbatim strings, and pin the protocol explicitly.
func verbatimSafe(opts *redis.Options) bool {
    return opts.Protocol == 3 && !behindRewritingProxy(opts.Addr) // your own check
}

Type guard

func isVerbatimParseError(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "redis: can't parse verbatim string reply:")
}

Try / catch

res, err := client.Do(ctx, "DEBUG", "JMAP", key).Result()
if err != nil {
    if isVerbatimParseError(err) {
        // fallback: re-issue with RESP2 semantics or parse raw string yourself
        res, err = fallbackPlainString(ctx, client, key)
    }
    if err != nil { return err }
}

Prevention

When it happens

Trigger: Calling any command that returns a RESP3 verbatim string ('=' reply) — such as DEBUG SLEEP, DEBUG JMAP, or module commands emitting verbatim strings — while the server returns a verbatim payload without the 'txt:'/'mkd:' prefix. Also triggered when a non-Redis or proxy server (e.g. a RESP proxy or a Twemproxy/envoy layer) replies with a bare bulk-like string using the '=' type instead of '$'. ReadReply() and ReadString() funnel through readVerb, so any of those surfaces the error.

Common situations: Talking to a RESP proxy or middleware that misformats verbatim replies; connecting to a Redis-compatible server (e.g. KeyDB fork quirks or an embedded/embedded-in-memory RESP implementation) that emits '=' replies without the type prefix; running with Protocol: 3 against a server that only partially implements RESP3; calling commands that shouldn't return verbatim strings against the wrong endpoint (e.g. sending an admin/debug command to a load balancer).

Related errors


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