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, nilView on GitHub (pinned to c5cad058c7)
Solutions
- 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{}.
- Force RESP2 on that connection (Protocol: 2) so map replies are delivered as flat arrays and never hit the RESP3 map parser.
- 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).
- 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
- Return flat arrays (key/value pairs) from Lua scripts and functions instead of tables/maps with composite keys.
- Audit all EVAL/EVALSHA/FCALL scripts when migrating to Protocol: 3 — shapes that worked under RESP2 can become maps under RESP3.
- Keep module commands' reply shapes documented and assert them in integration tests.
- Prefer Protocol: 2 for codebases with legacy scripts until they are rewritten.
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
- redis: can't parse verbatim string reply: %q
- bigInt(%s) value out of range
- redis: invalid map key %#v
- redis: can't parse int reply: %.100q
- redis: got %d elements in latency get, expected at least 4
AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01).
Data as JSON: /api/errors/70804bf687ac8653.
Report an issue: GitHub.