redis/redis-py · error · RedisClusterException

No way to dispatch this command to Redis Cluster. Missing ke

Error message

No way to dispatch this command to Redis Cluster. Missing key.
You can execute the command by specifying target nodes.
Command: {args}

What it means

Raised by _determine_slot() when a command yields zero keys (per COMMAND INFO key extraction) and is not FCALL/FCALL_RO. Redis Cluster routes by key hash slot, so a keyless command has no determinable destination. The library will not pick a random shard for arbitrary commands; the caller must name the target explicitly.

Source

Thrown at redis/asyncio/cluster.py:1013

        if command.upper() in ("EVAL", "EVALSHA"):
            # command syntax: EVAL "script body" num_keys ...
            if len(args) < 2:
                raise RedisClusterException(
                    f"Invalid args in command: {command, *args}"
                )
            keys = args[2 : 2 + int(args[1])]
            # if there are 0 keys, that means the script can be run on any node
            # so we can just return a random slot
            if not keys:
                return random.randrange(0, REDIS_CLUSTER_HASH_SLOTS)
        else:
            keys = await self.commands_parser.get_keys(command, *args)
            if not keys:
                # FCALL can call a function with 0 keys, that means the function
                #  can be run on any node so we can just return a random slot
                if command.upper() in ("FCALL", "FCALL_RO"):
                    return random.randrange(0, REDIS_CLUSTER_HASH_SLOTS)
                raise RedisClusterException(
                    "No way to dispatch this command to Redis Cluster. "
                    "Missing key.\nYou can execute the command by specifying "
                    f"target nodes.\nCommand: {args}"
                )

        # single key command
        if len(keys) == 1:
            return self.keyslot(keys[0])

        # multi-key command; we need to make sure all keys are mapped to
        # the same slot
        slots = {self.keyslot(key) for key in keys}
        if len(slots) != 1:
            raise RedisClusterException(
                f"{command} - all keys must map to the same key slot"
            )

        return slots.pop()

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Pass target_nodes to name the destination: rc.execute_command('DBSIZE', target_nodes='PRIMARIES') or rc.info(target_nodes=node).
  2. Use a node-flag constant such as RedisCluster.PRIMARIES / RANDOM / ALL_NODES for fan-out admin commands.
  3. For a single-shard call, resolve the node via rc.get_node(host=..., port=...) and pass it as target_nodes.

Example fix

// before
await rc.dbsize()

// after
await rc.dbsize(target_nodes=RedisCluster.PRIMARIES)
Defensive patterns

Strategy: validation

Validate before calling

from redis.asyncio.cluster import RedisCluster

KEYLESS_ADMIN_COMMANDS = {'INFO', 'DBSIZE', 'FLUSHDB', 'FLUSHALL', 'CONFIG', 'CLIENT', 'CLUSTER'}

async def run_keyless(rc: RedisCluster, command: str, *args, target='PRIMARIES'):
    if command.upper().split()[0] in KEYLESS_ADMIN_COMMANDS:
        return await rc.execute_command(command, *args, target_nodes=target)
    return await rc.execute_command(command, *args)

Type guard

from typing import Any
from redis.asyncio.cluster import RedisCluster

def needs_target_nodes(rc: RedisCluster, command: str) -> bool:
    # Crude heuristic: commands the COMMAND parser extracts 0 keys from
    keys = rc.commands_parser  # ensure initialized
    return command.upper() not in ('FCALL', 'FCALL_RO')

Try / catch

from redis.cluster import RedisClusterException

try:
    await rc.execute_command('DBSIZE')
except RedisClusterException as e:
    if 'Missing key' in str(e):
        await rc.execute_command('DBSIZE', target_nodes=RedisCluster.PRIMARIES)
    else:
        raise

Prevention

When it happens

Trigger: Calling rc.execute_command('INFO'), rc.execute_command('DBSIZE'), rc.config_get(), rc.flushdb() etc. without target_nodes, where the command's request policy is key-based (DEFAULT_KEYED) and no key argument is present. Also triggered by custom/unknown commands the COMMAND parser cannot extract keys from.

Common situations: Porting standalone-Redis code (rc.info(), rc.dbsize()) to RedisCluster without adding target_nodes; issuing admin/inspection commands that are inherently keyless; using a command the connected server doesn't know so COMMAND INFO returns no key specs.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/e8fd64e8af38d29b.json. Report an issue: GitHub.