go-redis/redis · error

redis: COLLECT value has type %T, want array of entries

Error message

redis: COLLECT value has type %T, want array of entries

What it means

Returned by AggregateRow.Collect (via parseCollectValue) when the value stored under the requested alias is present but is not a []interface{}. The COLLECT reducer column is expected to be an array of per-entry maps/arrays, so any other concrete Go type (string, int64, map, nil-nonzero) is treated as a malformed/foreign value. The '%T' slot is filled with the actual Go type to aid diagnosis.

Source

Thrown at search_collect.go:192

// preserved as returned by the server; it is meaningful only when the COLLECT
// reducer was given a SORTBY.
func (r AggregateRow) Collect(alias string) (CollectColumn, error) {
	v, ok := r.Fields[alias]
	if !ok {
		return nil, nil
	}
	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) {

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Verify the alias passed to row.Collect matches the AS alias of a COLLECT reducer you actually added (and does not collide with other reducers/fields).
  2. Check REDIS_VERSION / search-enable-unstable-features is enabled on the server; COLLECT needs Redis 8.8+.
  3. Inspect row.Fields[alias] (or cmd.RawVal()) to see the actual type and shape returned by the server, then correct the alias or the reducer setup.
  4. If the alias legitimately holds a non-array under some rows, branch on type before calling Collect instead of assuming the shape.

Example fix

// before
col, err := row.Collect("price") // "price" is a plain LOAD field, not COLLECT
// after
col, err := row.Collect("collected_items") // matches NewCollectReducer(... As: "collected_items")
Defensive patterns

Strategy: type-guard

Type guard

func isCollectColumn(v interface{}) bool {
	if v == nil { return true }
	_, ok := v.([]interface{})
	return ok
}

// guard before calling Collect:
if v, ok := row.Fields[alias]; ok && !isCollectColumn(v) {
    return fmt.Errorf("alias %q is not a COLLECT column: %T", alias, v)
}

Try / catch

col, err := row.Collect(alias)
if err != nil {
    // alias is not a COLLECT column or server reply is malformed;
    // fall back to reading the raw value or skip the row
    log.Printf("collect decode failed for %q: %v", alias, err)
    return nil, err
}

Prevention

When it happens

Trigger: Calling row.Collect("myAlias") when "myAlias" is not actually a COLLECT output column (e.g. it collides with a regular GROUPBY reducer alias, a LOAD field, or an APPLY expression). Also possible after a server/protocol mismatch where the alias resolves to a scalar or a raw map instead of an array.

Common situations: Alias name collision: the COLLECT AS alias matches another reducer's alias or a projected field name. Reading a RESP3 vs RESP2 reply through an unexpected protocol setting. Server version that does not support COLLECT (requires Redis 8.8+ with search-enable-unstable-features) returning an error-shaped scalar under the same key. Calling Collect on an alias that was never declared as a COLLECT reducer.

Related errors


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