go-redis/redis · error

unexpected type %T, want map or key/value array

Error message

unexpected type %T, want map or key/value array

What it means

Returned by parseCollectEntry when an individual COLLECT entry is neither a map (RESP3 map[interface{}]interface{} or map[string]interface{}) nor a flat key/value array ([]interface{}). The '%T' shows the actual Go type, e.g. string or int64, that appeared where an entry map was expected.

Solutions

  1. Inspect the raw reply (cmd.RawVal()) to identify the scalar and where it came from.
  2. Confirm the alias is exclusively used by a COLLECT reducer and not shared with another reducer/field.
  3. Verify the negotiated protocol (RESP2 vs RESP3) matches the server's reply type.
  4. Check server/proxy version and logs for an upstream error that was serialized into the results array.
Defensive patterns

Strategy: type-guard

Type guard

func isCollectEntryShape(e interface{}) bool {
	switch e.(type) {
	case map[interface{}]interface{}, map[string]interface{}, []interface{}:
		return true
	}
	return false
}

Try / catch

col, err := row.Collect(alias)
if err != nil {
    raw, _ := cmd.RawResult()
    log.Printf("COLLECT entry malformed on %q; raw=%v err=%v", alias, raw, err)
    return nil, err
}

Prevention

When it happens

Trigger: AggregateRow.Collect over an array whose element is a scalar (string, number, bulk-string error) rather than a per-entry map/array. Triggered purely during response decoding.

Common situations: Server returned an error string inline in the results array instead of as a top-level error. Protocol mismatch (RESP3 expected, RESP2 returned, or vice versa) causing the decoder to see a bare scalar. A non-COLLECT reducer's output landing in the same alias. Proxy rewriting the reply.

Related errors


AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06). Data as JSON: /api/errors/78dc7dd367c5fee3. Report an issue: GitHub.

Appendix: source

Thrown at search_collect.go:233

		}
		return out, nil
	case map[string]interface{}: // already string-keyed
		return m, nil
	case []interface{}: // RESP2 flat [field, value, field, value, ...]
		if len(m)%2 != 0 {
			return nil, fmt.Errorf("odd-length key/value array of length %d", len(m))
		}
		out := make(CollectEntry, len(m)/2)
		for i := 0; i < len(m); i += 2 {
			key, ok := m[i].(string)
			if !ok {
				key = fmt.Sprint(m[i])
			}
			out[key] = m[i+1]
		}
		return out, nil
	default:
		return nil, fmt.Errorf("unexpected type %T, want map or key/value array", e)
	}
}

View on GitHub (pinned to 36d97525cd)