redis/go-redis · error

redis: unexpected response %#v

Error message

redis: unexpected response %#v

What it means

In the same reply transformer as error 61, the RESP2 branch expects the reply to be a []interface{} of []interface{} pairs (array of [key, value] arrays). If an element is not a []interface{}, it cannot be turned into a map, so the parser returns `redis: unexpected response` with the whole reply printed via %#v.

Source

Thrown at command.go:6374

		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 {
					return fmt.Errorf("redis: invalid map key %#v", finalArr[i])
				}
				resultMap[stringKey] = finalArr[j+1] // second one is value
			}
		}
	default:
		return fmt.Errorf("redis: unexpected response %#v", data)
	}

View on GitHub (pinned to c5cad058c7)

Solutions

  1. Read the %#v dump in the error — it shows the exact reply shape the server sent; compare with what your Redis version should return.
  2. Try `Protocol: 3` (RESP3) so the map-native branch of the transformer is used instead of the array-of-arrays path.
  3. Upgrade go-redis and/or the server so both agree on the reply format.
  4. If a proxy is in the path, inspect and fix its reply translation, or bypass it for this command.

Example fix

// before: RESP2 reply flattened by a proxy
cfg := &redis.Options{Addr: addr, Protocol: 2}

// after: use RESP3 so maps arrive as maps
cfg := &redis.Options{Addr: addr, Protocol: 3}
Defensive patterns

Strategy: try-catch

Type guard

func isArrayOfPairArrays(v interface{}) bool {
    arr, ok := v.([]interface{})
    if !ok {
        return false
    }
    for _, e := range arr {
        if _, ok := e.([]interface{}); !ok {
            return false
        }
    }
    return true
}

Try / catch

res, err := cmd.Result()
if err != nil {
    if strings.Contains(err.Error(), "unexpected response") {
        // log raw reply shape captured via ProcessHook, then fall back
        log.Printf("unexpected reply shape: %v", err)
        return nil, errReplyShape
    }
    return err
}

Prevention

When it happens

Trigger: Calling a command routed through this map transformer under RESP2 when the server/proxy returns a flat array, a scalar, or nested structures instead of an array of 2-element arrays — typically with FUNCTION LIST-like replies from a non-Redis server or a version whose shape changed.

Common situations: Redis-compatible servers (Dragonfly, KeyDB) or proxies reshaping replies; server version newer than the client expects; RESP2 vs RESP3 mismatches (Protocol: 2 vs 3) selecting the other code path.

Related errors


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