go-redis/redis · error
redis: COLLECT entry %d: %w
Error message
redis: COLLECT entry %d: %w
What it means
Wraps a per-entry decoding failure inside parseCollectValue: the COLLECT alias value is an array, but element at index %d could not be decoded by parseCollectEntry (odd-length key/value array or unexpected entry type). The '%w' verb preserves the underlying error for errors.Is/As. The index is zero-based into the server-returned entry array.
Source
Thrown at search_collect.go:198
}
return parseCollectValue(v)
}
// parseCollectValue decodes a raw COLLECT alias value (an array of entries)
// into a CollectColumn.
func parseCollectValue(v interface{}) (CollectColumn, error) {
if v == nil {
return nil, nil
}
arr, ok := v.([]interface{})
if !ok {
return nil, fmt.Errorf("redis: COLLECT value has type %T, want array of entries", v)
}
out := make(CollectColumn, 0, len(arr))
for i, e := range arr {
entry, err := parseCollectEntry(e)
if err != nil {
return nil, fmt.Errorf("redis: COLLECT entry %d: %w", i, err)
}
out = append(out, entry)
}
return out, nil
}
// parseCollectEntry decodes a single collected entry from either the RESP3
// map form or the RESP2 flat key/value array form into a CollectEntry. Keys
// are passed through as-is: the server already returns them without the "@"
// prefix.
func parseCollectEntry(e interface{}) (CollectEntry, error) {
switch m := e.(type) {
case map[interface{}]interface{}: // RESP3
out := make(CollectEntry, len(m))
for k, val := range m {
out[fmt.Sprint(k)] = val
}
return out, nilView on GitHub (pinned to 36d97525cd)
Solutions
- Inspect cmd.RawVal() to see the exact shape of the offending entry at the reported index.
- Confirm the server supports COLLECT (Redis 8.8+) and that the protocol (RESP2 vs RESP3) matches what the client negotiated.
- If you cannot upgrade the server, avoid COLLECT or reduce the projected fields to isolate which field triggers the bad shape.
- Reproduce with redis-cli / RESP3 to determine whether the malformed entry comes from the server or from an intermediate proxy.
Defensive patterns
Strategy: try-catch
Try / catch
col, err := row.Collect(alias)
if err != nil {
// one of the entries was malformed; the wrapped error names entry index and cause
var decodeErr *collectEntryError // if you wrap/define one
if errors.As(err, &decodeErr) { /* handle specific shape */ }
return fmt.Errorf("COLLECT decode failed on alias %q: %w", alias, err)
} Prevention
- Pin the server Redis version that supports COLLECT (8.8+) in your test/prod images.
- Match the client's negotiated protocol to the server's reply type (RESP2/RESP3).
- Capture cmd.RawVal() in telemetry when COLLECT decoding fails to identify the offending entry.
When it happens
Trigger: AggregateRow.Collect succeeds in finding the alias and reading it as an array, but one of the entries is malformed (e.g. a bare string/number instead of a map or flat array, or a RESP2 flat array with an odd element count). Triggered during response decoding, so the server reply shape is the root cause.
Common situations: Server version/protocol drift producing a non-conforming COLLECT entry. RESP2/RESP3 negotiation mismatch where entries arrive in an unexpected representation. A schema change causing one entry to be projected differently. Proxy or resp-mangling middleware corrupting the frame.
Related errors
- redis: COLLECT value has type %T, want array of entries
- odd-length key/value array of length %d
- unexpected type %T, want map or key/value array
- redis: FT.AGGREGATE COLLECT: empty field name in SortBy
- redis: FT.AGGREGATE COLLECT: ASC and DESC are mutually exclu
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/9920f1281a2b379d.json.
Report an issue: GitHub.