redis/redis-py · error · RedisClusterException
Too many targets for command
Error message
Too many targets for command {cmd.args} What it means
Raised in ClusterPipeline._execute() when a queued command resolves to more than one target node. The transactional/non-transactional pipeline strategies send each queued command to exactly one node (cluster pipelines are slot-pinned per command), so a command that would fan out to multiple nodes is rejected because the pipeline cannot represent a multi-node result for one entry.
Solutions
- Pin each queued command to a single node: pass target_nodes=<one ClusterNode> or a single node-flag that resolves to one node.
- For cross-key bulk writes use mset_nonatomic() which splits per slot, or run separate pipelines per slot.
- For commands you genuinely want on every node, execute them directly via execute_command(target_nodes=rc.ALL_NODES) outside the pipeline.
- Ensure multi-key pipeline commands share a hash tag so they resolve to one slot.
Example fix
// before
pipe = rc.pipeline()
pipe.execute_command('CONFIG', 'REWRITE', target_nodes=rc.ALL_NODES) # >1 node
await pipe.execute()
// after
await rc.execute_command('CONFIG', 'REWRITE', target_nodes=rc.ALL_NODES)
# or pin the pipeline entry:
pipe = rc.pipeline()
pipe.execute_command('CONFIG', 'REWRITE', target_nodes=rc.get_primaries()[0])
await pipe.execute() Defensive patterns
Strategy: type-guard
Validate before calling
def single_node_targets(rc, target_nodes):
nodes = rc._parse_target_nodes(target_nodes)
if len(nodes) > 1:
raise ValueError('pipeline commands require exactly one target node')
return nodes
pipe = rc.pipeline()
pipe.execute_command('CONFIG', 'REWRITE',
target_nodes=rc.get_primaries()[0]) Type guard
def is_single_target(rc, t) -> bool:
try:
return len(rc._parse_target_nodes(t)) == 1
except TypeError:
return False Try / catch
from redis.exceptions import RedisClusterException
try:
await pipe.execute()
except RedisClusterException as e:
if 'Too many targets' in str(e):
# move the offending command out of the pipeline and run it directly
await rc.execute_command(*cmd.args, target_nodes=rc.ALL_NODES) Prevention
- Pin each pipeline command to one node or to keys sharing a hash tag/slot.
- Run fan-out commands (ALL_NODES/PRIMARIES) outside the pipeline.
- Use mset_nonatomic() for cross-slot bulk writes.
When it happens
Trigger: Queuing a command with an ALL_NODES/PRIMARIES policy or passing target_nodes=[nodeA, nodeB] to a single pipeline entry. Also a multi-key command whose keys do not share a slot when the pipeline is in transaction mode (single-slot constraint).
Common situations: Treating a cluster pipeline like the standalone pipeline and expecting fan-out; pipelining cross-slot keys; passing a list of nodes as target_nodes for one queued command.
Related errors
- At least a command with a key is needed to identify a node
- Cannot identify slot number for command
- All keys involved in a cluster transaction must map to the…
- Cannot watch or send commands on different slots
- Cannot watch or send commands on different slots
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/ad98db08b98985a6.
Report an issue: GitHub.
Appendix: source
Thrown at redis/asyncio/cluster.py:2945
request_policy=client._command_flags_mapping[
command_flag
]
)
else:
command_policies = CommandPolicies()
target_nodes = await client._determine_nodes(
*cmd.args,
request_policy=command_policies.request_policy,
node_flag=passed_targets,
)
if not target_nodes:
raise RedisClusterException(
f"No targets were found to execute {cmd.args} command on"
)
cmd.command_policies = command_policies
if len(target_nodes) > 1:
raise RedisClusterException(f"Too many targets for command {cmd.args}")
node = target_nodes[0]
if node.name not in nodes:
nodes[node.name] = (node, [])
nodes[node.name][1].append(cmd)
# Start timing for observability
start_time = time.monotonic()
errors = await asyncio.gather(
*(
asyncio.create_task(node[0].execute_pipeline(node[1]))
for node in nodes.values()
)
)
# Record operation duration for each node
for node_name, (node, commands) in nodes.items():
# Find the first error in this node's commands, if anyView on GitHub (pinned to 6a6b581b48)