redis/go-redis · error

redis: RESP3 map key must be a scalar type, got %T

Error message

redis: RESP3 map key must be a scalar type, got %T

What it means

go-redis parses RESP3 map replies into a Go map[interface{}]interface{}, so every key must be hashable (a scalar: string, int, bool, etc.). When the server sends a map whose key is itself an array or a nested map, such a value cannot be used as a Go map key (it would panic), so the library detects []interface{} and map[interface{}]interface{} keys and returns this error instead. This is a deliberate guard: it protects the caller from a runtime panic deep inside map assignment.

Source

Thrown at internal/proto/reader.go:469

func (r *Reader) readMap(line []byte) (map[interface{}]interface{}, error) {
	n, err := replyLen(line)
	if err != nil {
		return nil, err
	}
	m := make(map[interface{}]interface{}, n)
	for i := 0; i < n; i++ {
		k, err := r.ReadReply()
		if err != nil {
			return nil, err
		}

		// Reject unhashable keys (arrays/maps) before they are used as a map
		// key, which would otherwise panic. This check must run before the
		// value is read so it also guards the Nil and RedisError paths below,
		// which write the key into the map and continue.
		switch k.(type) {
		case []interface{}, map[interface{}]interface{}:
			return nil, fmt.Errorf("redis: RESP3 map key must be a scalar type, got %T", k)
		}

		v, err := r.ReadReply()
		if err != nil {
			if err == Nil {
				m[k] = nil
				continue
			}
			if err, ok := err.(RedisError); ok {
				m[k] = err
				continue
			}
			return nil, err
		}

		m[k] = v
	}
	return m, nil

View on GitHub (pinned to c5cad058c7)

Solutions

  1. Change the Lua script / module command so it returns a flat array (key and value as consecutive elements) instead of a table/map with composite keys, then read the result as []interface{}.
  2. Force RESP2 on that connection (Protocol: 2) so map replies are delivered as flat arrays and never hit the RESP3 map parser.
  3. If the reply shape is unavoidable, use a raw/custom command that returns the data via a type you control (e.g. have the script JSON-encode the structure and decode it in Go).
  4. Upgrade go-redis: check the release notes — the guard itself was added to convert a panic into this error, so newer versions handle edge shapes differently.

Example fix

-- before: Lua returns a map keyed by an array (RESP3 map with composite key)
return {[{1,2}] = "v"}
-- after: return a flat array instead
return {1, 2, "v"}
Defensive patterns

Strategy: type-guard

Validate before calling

// Pre-validate what the Lua/module command will return: inspect the script's
// return shape in staging with redis-cli --eval and confirm keys are scalars.

Type guard

func isScalarReply(v interface{}) bool {
    switch v.(type) {
    case []interface{}, map[interface{}]interface{}:
        return false
    }
    return true
}

Try / catch

res, err := client.Do(ctx, "EVAL", script, "1", key).Result()
if err != nil {
    if strings.HasPrefix(err.Error(), "redis: RESP3 map key must be a scalar type") {
        return fmt.Errorf("script returns non-scalar map keys; rewrite script to return a flat array: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Any command whose RESP3 reply is a map type ('%') with a non-scalar key — practically this comes from custom Lua scripts (EVAL/EVALSHA) or Redis functions (FCALL) that return a map keyed by an array/table, or from modules that construct RESP3 maps with array keys. It fires inside ReadReply() while parsing the response of any Cmdable method, most commonly EVAL/EVALSHA/FCALL or generic Do() calls.

Common situations: Migrating a Lua script to RESP3 (Protocol: 3): under RESP2 the same script returned a flat array and worked; under RESP3 Redis converts Lua table replies with mixed keys to a RESP3 map, surfacing array keys. Copying a script written for another client library that tolerates non-scalar keys. A module or custom command emitting maps with composite keys.

Related errors


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