A Redis cluster MOVED error means a client tried to talk to a Redis node that doesn’t own the hash slot for that key, and that node is telling the client to go to the correct node. This usually happens because the client isn’t aware of the cluster’s topology, or the topology has changed and the client hasn’t updated its routing table.
Here are the common causes and how to fix them:
Client Not Aware of Cluster Topology
Diagnosis: Most Redis clients have a way to discover the cluster topology. If this isn’t enabled or is failing, the client will send commands to an arbitrary node.
Cause 1: Client not initialized in cluster mode. Many Redis client libraries require a specific flag or constructor to enable cluster mode. If this is missed, the client will behave like a standalone Redis client.
- Command/Check: Look at your client’s initialization code. For example, in
redis-py, you’d useRedisClusterinstead ofRedis. In Node.jsioredis, you’d passcluster: trueor an array of cluster nodes. - Fix: Ensure your client library is instantiated with cluster awareness.
redis-pyexample:from rediscluster import RedisCluster # Incorrect for cluster: # r = redis.Redis(host='127.0.0.1', port=7000) # Correct for cluster: rc = RedisCluster(startup_nodes=[{"host": "127.0.0.1", "port": "7000"}], decode_responses=True) rc.set("mykey", "myvalue") # This will now handle MOVED redirects internallyioredisexample (Node.js):const Redis = require('ioredis'); // Incorrect for cluster: // const redis = new Redis(7000, '127.0.0.1'); // Correct for cluster: const cluster = new Redis.Cluster([ { host: '127.0.0.1', port: 7000 }, { host: '127.0.0.1', port: 7001 }, { host: '127.0.0.1', port: 7002 }, ]); cluster.set('mykey', 'myvalue'); // Handles redirects
- Why it works: These clients, when properly initialized in cluster mode, will automatically query the cluster for slot ownership. When they receive a
MOVEDerror, they update their internal mapping of hash slots to nodes and resend the command to the correct node.
Cause 2: Client using a single node as a seed, and that node is down or not the master for the slot.
If your client is configured with only one seed node, and that node is not the master responsible for the hash slot of the key you’re accessing, it will likely return a MOVED error.
- Command/Check: Examine your client’s configuration for the list of initial nodes.
- Fix: Provide multiple seed nodes in your client configuration, ideally all master nodes in the cluster. This increases the chance that the client will connect to a node that can provide accurate topology information.
redis-pyexample:rc = RedisCluster(startup_nodes=[ {"host": "192.168.1.100", "port": 7000}, {"host": "192.168.1.101", "port": 7001}, {"host": "192.168.1.102", "port": 7002} ], decode_responses=True)
- Why it works: With multiple seed nodes, the client has a higher probability of connecting to a node that is a master and can correctly inform the client about the cluster’s slot distribution. If one seed node is down or misconfigured, others can still bootstrap the topology.
Cluster Topology Changes
Cause 3: Cluster rebalancing or node failures causing slot migration. When Redis Cluster rebalances slots (e.g., adding/removing nodes) or when a master node fails and a replica is promoted, the ownership of hash slots changes. If a client has an outdated view of the cluster, it will send commands to the wrong node.
- Command/Check: Use
redis-cli --cluster check <node_ip>:<node_port>to inspect the current slot distribution. Compare this to what your client might know. TheMOVEDerror itself is the primary symptom. - Fix: Most modern cluster-aware clients will automatically refresh their topology information when they encounter a
MOVEDerror. However, if the client is stale and not actively refreshing, you might need to explicitly trigger a refresh or reconnect.redis-py: TheRedisClusterclient automatically handles this. If you suspect issues, you can tryrc.refresh_cluster()(though this is less common asMOVEDerrors trigger it implicitly).ioredis: Similar toredis-py,iorediscluster mode handles this. You can force a refresh of the cluster topology withcluster.nodes().
- Why it works: The
MOVEDerror is the cluster’s mechanism to tell clients, "Hey, you’re talking to the wrong guy for this key. Go ask this node instead." A correctly implemented client will then update its internal routing table based on theMOVEDresponse.
Cause 4: Client connecting to a replica node instead of a master. If a client connects to a replica node and tries to write data (or perform an operation that requires the master), the replica will redirect the client to the master responsible for that key’s slot.
- Command/Check:
- Identify the node your client is connecting to when the error occurs.
- Run
CLUSTER NODESon that node. Look formasterorslavein the flags. - If it’s a
slave, note its corresponding master. - Run
CLUSTER NODESon the master to confirm slot ownership.
- Fix: Ensure your client is configured to connect to master nodes, or that it’s capable of handling redirects from replicas to masters. Most cluster clients will do this. If you’re manually directing traffic, ensure it goes to masters for writes.
- Configuration: When listing seed nodes for your client, prioritize masters. If your client library supports it, you can often configure it to prefer masters for writes and replicas for reads (though this can add complexity).
- Why it works: The
MOVEDerror from a replica explicitly points the client to the correct master. The client’s cluster mode logic then takes over, updates its routing table, and retries the command on the master.
Network or Configuration Issues
Cause 5: Network partitions or firewall blocking communication between nodes.
If nodes in the cluster cannot communicate with each other, they might not have a consistent view of the cluster state, leading to incorrect slot assignments or nodes appearing down. This can indirectly cause MOVED errors if a client connects to a node that thinks it owns a slot but doesn’t, or if it’s unaware of a failover.
- Command/Check:
- On each node, run
redis-cli -c -p <port> CLUSTER NODES. Check if all nodes see each other and have the correct state (connectedflag). - Use
pingortraceroutebetween nodes to check basic network connectivity. - Check firewall rules (
iptables,ufw, cloud security groups) on all nodes to ensure ports16379(Redis client port) and16379+10000(Redis cluster bus port, e.g.,26379for16379) are open between all nodes.
- On each node, run
- Fix: Resolve network connectivity issues and open necessary ports.
- Firewall Example (
ufwon Debian/Ubuntu):# Allow client connections on port 6379 sudo ufw allow 6379/tcp # Allow cluster bus communication on port 16379 (assuming default 6379 client port) sudo ufw allow 16379/tcp # If you have multiple nodes, you'll need to allow from specific IPs or ranges # For example, to allow from a specific node IP: # sudo ufw allow from 192.168.1.101 to any port 6379 proto tcp # sudo ufw allow from 192.168.1.101 to any port 16379 proto tcp
- Firewall Example (
- Why it works: Redis Cluster relies on nodes being able to gossip cluster state. If they can’t communicate, the cluster state becomes inconsistent. Fixing network issues allows nodes to synchronize, ensuring correct slot ownership and routing.
Cause 6: cluster-require-full-coverage is set to yes and some slots are unassigned.
This cluster configuration option (cluster-require-full-coverage yes) means that if any hash slot is not assigned to any master node, the cluster will refuse commands that target those slots. This can manifest as MOVED errors if a client tries to access a key in an unassigned slot, or if the cluster state is temporarily inconsistent during rebalancing.
- Command/Check:
- Run
redis-cli -c -p <port> CONFIG GET cluster-require-full-coverage. - Run
redis-cli -c -p <port> CLUSTER SLOTS. Check if there are any gaps in the slot ranges.
- Run
- Fix: Either ensure all 16384 slots are assigned to master nodes, or set
cluster-require-full-coveragetono. Setting it tonomeans that commands targeting unassigned slots will result in an error likeCLUSTERDOWNorERR.- To set to
no:redis-cli -c -p <port> CONFIG SET cluster-require-full-coverage no # You might need to do this on all nodes or restart them for the config to stick # Alternatively, edit redis.conf and set it to 'no', then restart Redis. - To assign all slots: If you are adding nodes or rebalancing, ensure the process completes successfully, assigning all slots. Use
redis-cli --cluster fix <node_ip>:<node_port>to attempt to fix slot assignments if they are broken.
- To set to
- Why it works: If set to
no, the cluster will accept commands even if slots are unassigned, returning an error indicating the slot is not covered. This is generally preferred overyesunless you have a strict requirement that all slots must be covered to proceed, and you want to fail fast if they aren’t.
The next error you’ll likely hit is a CLUSTERDOWN error if you’ve fixed the MOVED redirects but the cluster itself is in a bad state (e.g., insufficient masters for certain slots when cluster-require-full-coverage is yes).