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, nil

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Inspect cmd.RawVal() to see the exact shape of the offending entry at the reported index.
  2. Confirm the server supports COLLECT (Redis 8.8+) and that the protocol (RESP2 vs RESP3) matches what the client negotiated.
  3. If you cannot upgrade the server, avoid COLLECT or reduce the projected fields to isolate which field triggers the bad shape.
  4. 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

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


AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06). Data as JSON: /data/errors/9920f1281a2b379d.json. Report an issue: GitHub.