redis/go-redis · error

redis: invalid map key %#v

Error message

redis: invalid map key %#v

What it means

Thrown by the reply normalizer for commands like `FUNCTION DUMP`/`FCALL` consumers that flatten RESP3 maps into map[string]interface{} (command.go, case map[interface{}]interface{}). RESP3 maps may have non-string keys; this transformer only supports string keys, so any non-string key (integer, nested value, etc.) makes it abort with `redis: invalid map key`.

Source

Thrown at command.go:6365

func (cmd *MapMapStringInterfaceCmd) Val() map[string]interface{} {
	cmd.await()
	return cmd.val
}

// readReply will try to parse the reply from the proto.Reader for both resp2 and resp3
func (cmd *MapMapStringInterfaceCmd) readReply(rd *proto.Reader) (err error) {
	data, err := rd.ReadReply()
	if err != nil {
		return err
	}
	resultMap := map[string]interface{}{}

	switch midResponse := data.(type) {
	case map[interface{}]interface{}: // resp3 will return map
		for k, v := range midResponse {
			stringKey, ok := k.(string)
			if !ok {
				return fmt.Errorf("redis: invalid map key %#v", k)
			}
			resultMap[stringKey] = v
		}
	case []interface{}: // resp2 will return array of arrays
		n := len(midResponse)
		for i := 0; i < n; i++ {
			finalArr, ok := midResponse[i].([]interface{}) // final array that we need to transform to map
			if !ok {
				return fmt.Errorf("redis: unexpected response %#v", data)
			}
			m := len(finalArr)
			if m%2 != 0 { // since this should be map, keys should be even number
				return fmt.Errorf("redis: unexpected response %#v", data)
			}

			for j := 0; j < m; j += 2 {
				stringKey, ok := finalArr[j].(string) // the first one
				if !ok {

View on GitHub (pinned to c5cad058c7)

Solutions

  1. Upgrade go-redis to the latest v9 release — the transformers are updated regularly to accept new server reply shapes.
  2. Compare the reply against a supported server version (`INFO server`); pin to a Redis version known to work with your go-redis release.
  3. Capture the raw reply with `redis-cli --raw <command>` or a ProcessHook to see the offending key type, then file/consult a go-redis issue.
  4. If you control the reply source (test mock), make all map keys strings.

Example fix

// before: Protocol not set, server/module returns map with int keys
opt := &redis.Options{Addr: addr}

// after: pin RESP2 (array-of-arrays path) or upgrade go-redis that handles the new shape
opt := &redis.Options{Addr: addr, Protocol: 2}
Defensive patterns

Strategy: validation

Validate before calling

// verify protocol and server version before commands relying on map replies
info, _ := rdb.Info(ctx, "server").Result()
if !strings.Contains(info, "redis_version:7") && !strings.Contains(info, "redis_version:8") {
    // older/unknown server: avoid map-normalized commands
}

Type guard

func isStringKeyMap(m map[interface{}]interface{}) bool {
    for k := range m {
        if _, ok := k.(string); !ok {
            return false
        }
    }
    return true
}

Try / catch

res, err := cmd.Result()
if err != nil {
    if strings.Contains(err.Error(), "invalid map key") {
        // dump raw reply via a ProcessHook for diagnosis, then fallback
        return fallbackParse(raw)
    }
    return err
}

Prevention

When it happens

Trigger: Calling a command whose reply is normalized through this transformer (e.g. `FunctionList`, FT/JSON helpers that use MapStringInterfaceCmd-style parsing) when the server returns a RESP3 map whose key is not a Go string — for example a Redis version or module emitting integer-valued keys in that map.

Common situations: Newer server versions adding fields/keys the transformer doesn't expect; mixing RESP2/RESP3 (Protocol: 3) with a module that returns unusual map keys; connecting to Redis Enterprise or a module whose reply shape differs from OSS Redis.

Related errors


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