redis/redis-py · error · TypeError

target_nodes type can be one of the following: node_flag…

Error message

target_nodes type can be one of the following: node_flag (PRIMARIES, REPLICAS, RANDOM, ALL_NODES),ClusterNode, list<ClusterNode>, or dict<any, ClusterNode>. The passed type is {type(target_nodes)}

What it means

Raised as a TypeError by _parse_target_nodes() when the target_nodes argument is not one of the accepted types: a node_flag string (PRIMARIES, REPLICAS, RANDOM, ALL_NODES), a ClusterNode instance, a list of ClusterNode, or a dict mapping names to ClusterNode. The guard at cluster.py:1527-1532 checks isinstance for each valid type and raises for anything else, including the type in the message.

Solutions

  1. Use the node_flag string constants: 'PRIMARIES', 'REPLICAS', 'ALL_NODES', or 'RANDOM'.
  2. Pass a ClusterNode obtained from client.get_node(host, port) or client.get_primaries().
  3. Pass a list of ClusterNode objects or a dict of {name: ClusterNode}.

Example fix

// before
client.execute_command('INFO', target_nodes='primary')

// after
client.execute_command('INFO', target_nodes='PRIMARIES')
Defensive patterns

Strategy: type-guard

Validate before calling

from redis.cluster import ClusterNode
valid_flags = {'PRIMARIES', 'REPLICAS', 'ALL_NODES', 'RANDOM'}
def validate_target_nodes(tn):
    if isinstance(tn, str) and tn not in valid_flags:
        raise TypeError(f'Invalid node_flag: {tn}. Use one of {valid_flags}')
    if not isinstance(tn, (str, ClusterNode, list, dict)):
        raise TypeError(f'Invalid target_nodes type: {type(tn)}')
    return tn

Type guard

from redis.cluster import ClusterNode
VALID_FLAGS = {'PRIMARIES', 'REPLICAS', 'ALL_NODES', 'RANDOM'}
def is_valid_target_nodes(tn) -> bool:
    if isinstance(tn, str):
        return tn in VALID_FLAGS
    if isinstance(tn, ClusterNode):
        return True
    if isinstance(tn, list):
        return all(isinstance(n, ClusterNode) for n in tn)
    if isinstance(tn, dict):
        return all(isinstance(v, ClusterNode) for v in tn.values())
    return False

Try / catch

null

Prevention

When it happens

Trigger: Passing target_nodes as a string that isn't a node_flag, an integer, a tuple, or any object that isn't ClusterNode or a container of ClusterNode, e.g. client.get('key', target_nodes=123) or target_nodes=' primaries' (typo).

Common situations: Passing the host:port string instead of a ClusterNode object, passing a single host string, or a typo in the node_flag constant name.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/2ea1b368971f80ae. Report an issue: GitHub.

Appendix: source

Thrown at redis/cluster.py:1527

        """
        return self.nodes_manager.connection_kwargs

    def _is_nodes_flag(self, target_nodes):
        return isinstance(target_nodes, str) and target_nodes in self.node_flags

    def _parse_target_nodes(self, target_nodes):
        if isinstance(target_nodes, list):
            nodes = target_nodes
        elif isinstance(target_nodes, ClusterNode):
            # Supports passing a single ClusterNode as a variable
            nodes = [target_nodes]
        elif isinstance(target_nodes, dict):
            # Supports dictionaries of the format {node_name: node}.
            # It enables to execute commands with multi nodes as follows:
            # rc.cluster_save_config(rc.get_primaries())
            nodes = target_nodes.values()
        else:
            raise TypeError(
                "target_nodes type can be one of the following: "
                "node_flag (PRIMARIES, REPLICAS, RANDOM, ALL_NODES),"
                "ClusterNode, list<ClusterNode>, or dict<any, ClusterNode>. "
                f"The passed type is {type(target_nodes)}"
            )
        return nodes

    def execute_command(self, *args, **kwargs):
        return self._internal_execute_command(*args, **kwargs)

    def _internal_execute_command(self, *args, **kwargs):
        """
        Wrapper for ERRORS_ALLOW_RETRY error handling.

        It will try the number of times specified by the retries property from
        config option "self.retry" which defaults to 10 unless manually
        configured.

View on GitHub (pinned to 6a6b581b48)