redis/redis-py · error · RedisClusterException

At least a command with a key is needed to identify a node

Error message

At least a command with a key is needed to identify a node

What it means

Raised in TransactionStrategy._get_client_and_connection_for_transaction (redis/cluster.py:4594) when self._pipeline_slots is empty. A cluster transaction must pin to a single slot's owning node; the slot is learned from the first keyed command. If a transactional operation needs a connection before any keyed command has been queued/watched, the strategy cannot pick a node.

Source

Thrown at redis/cluster.py:4595

        self._pipeline_slots: Set[int] = set()
        self._transaction_connection: Optional[Connection] = None
        self._executing = False
        self._retry = copy(self._pipe.retry)
        self._retry.update_supported_errors(
            RedisCluster.ERRORS_ALLOW_RETRY + self.SLOT_REDIRECT_ERRORS
        )

    def _get_client_and_connection_for_transaction(self) -> Tuple[Redis, Connection]:
        """
        Find a connection for a pipeline transaction.

        For running an atomic transaction, watch keys ensure that contents have not been
        altered as long as the watch commands for those keys were sent over the same
        connection. So once we start watching a key, we fetch a connection to the
        node that owns that slot and reuse it.
        """
        if not self._pipeline_slots:
            raise RedisClusterException(
                "At least a command with a key is needed to identify a node"
            )

        node: ClusterNode = self._nodes_manager.get_node_from_slot(
            list(self._pipeline_slots)[0], False
        )
        redis_node: Redis = self._pipe.get_redis_connection(node)
        if self._transaction_connection:
            if not redis_node.connection_pool.owns_connection(
                self._transaction_connection
            ):
                previous_node = self._nodes_manager.find_connection_owner(
                    self._transaction_connection
                )
                previous_node.connection_pool.release(self._transaction_connection)
                self._transaction_connection = None

        if not self._transaction_connection:

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Ensure at least one keyed command (GET/SET/HGET/...) is queued or watched before execute().
  2. Move keyless/admin commands (INFO, CONFIG, CLIENT) out of the transactional pipeline and call them on the client directly with target_nodes.
  3. If you only needed a MULTI/EXEC wrapper for keyless commands, drop the pipeline and call the client directly.

Example fix

# before
pipe = rc.pipeline(transaction=True)
pipe.multi()
pipe.info()           # keyless -> no slot
pipe.execute()        # raises: At least a command with a key is needed

# after
rc.info(target_nodes=RedisCluster.PRIMARIES)  # admin cmd on client
# or include a keyed command in the transaction:
pipe = rc.pipeline(transaction=True)
pipe.watch('k')
pipe.multi()
pipe.set('k', '1')
pipe.execute()
Defensive patterns

Strategy: validation

Validate before calling

def run_transaction(client, keyed_commands, keyless_commands=None):
    if not keyed_commands:
        raise ValueError('cluster transaction needs at least one keyed command to pin a node')
    pipe = client.pipeline(transaction=True)
    for args in keyed_commands:
        pipe.execute_command(*args)
    pipe.execute()
    # run keyless commands on the client, not in the transaction
    return pipe

Try / catch

from redis.exceptions import RedisClusterException

try:
    pipe.execute()
except RedisClusterException as e:
    if 'command with a key is needed' in str(e):
        rc.info(target_nodes=RedisCluster.PRIMARIES)  # move keyless cmd out of the txn
    else:
        raise

Prevention

When it happens

Trigger: Calling pipe.execute() on a transactional pipeline that contains only keyless commands (e.g. pipe.multi(); pipe.info(); pipe.execute()). Or calling an immediate-execute command that needs a connection before any slot has been recorded. WATCH with no key followed by an operation requiring a connection.

Common situations: Building a transaction from admin/keyless commands, which have no slot. Calling MULTI then immediately EXEC with nothing keyed in between. Logic that begins a transaction conditionally and sometimes queues no keyed command.

Related errors


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