redis/node-redis · error · Error
SCAN: no master nodes available
Error message
SCAN: no master nodes available
What it means
A cluster-wide SCAN starting from cursor '0' could not find any master node to route to. The cluster slots state has no known master addresses, so nextScanTarget returns undefined. This means the client has no topology or all nodes are unreachable.
Solutions
- Verify the cluster is healthy and at least one node is reachable via redis-cli
- Wait for the client to finish its initial slots discovery before starting a scan
- Check connectivity with a simple command (e.g., client.ping()) before initiating a scan
- Implement retry logic with backoff to wait for topology recovery
Defensive patterns
Strategy: retry
Validate before calling
// Check cluster health before scanning.
try {
await client.ping();
} catch {
throw new Error('Cluster is not reachable — cannot start SCAN');
} Try / catch
async function scanWithRetry(client, fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
for await (const keys of client.scanIterator()) {
await fn(keys);
}
return;
} catch (e) {
if (e.message === 'SCAN: no master nodes available' && i < maxRetries - 1) {
await new Promise(r => setTimeout(r, 1000 * (i + 1)));
continue;
}
throw e;
}
}
} Prevention
- Verify cluster connectivity before starting a scan
- Ensure the client has completed its initial slots refresh before scanning
- Implement retry with exponential backoff for transient cluster unavailability
When it happens
Trigger: Calling client.scan() or iterating scanIterator in cluster mode when the slots table has no master node addresses — the cluster is down, the client hasn't completed slots discovery, or all masters were removed from the topology.
Common situations: Cluster is down or unreachable; client connected but slots refresh hasn't completed; all master nodes removed during a major reshard; network partition isolating all nodes.
Related errors
- SCAN: node serving this cursor has left the cluster —…
- Cannot find node
- Could not find shard
- [Proxy] No destination node
- Request policy produced no target nodes
AI-assisted analysis of redis/node-redis@90fd0652bc (2026-08-11).
Data as JSON: /api/errors/2110222c4fe05c5c.
Report an issue: GitHub.
Appendix: source
Thrown at packages/client/lib/cluster/request-response-policies/scan-cursor.ts:40
* finally sees "0".
*
* The visited set is tracked by node address, so a topology change mid-scan
* neither rescans a surviving node nor gets stuck on a departed one. The usual
* SCAN guarantees apply per node; keys migrating between nodes mid-iteration
* may be missed or duplicated — same caveat as every cluster-wide scan.
*/
export const routeScan: RequestRouter = async (slots, parser) => {
// Malformed raw command (missing cursor): forward to any node so the server
// returns its own arity error instead of a client-side TypeError.
if (parser.redisArgs.length < 2) {
return [{ client: await slots.nodeClient(slots.getRandomNode()) }];
}
const cursorArg = argToString(parser.redisArgs[1]);
if (cursorArg === '0') {
const address = slots.nextScanTarget(EMPTY_VISITED);
if (!address) throw new Error('SCAN: no master nodes available');
return [{ client: await pinnedMaster(slots, address) }];
}
const entry = slots.lookupScanCursor(cursorArg);
if (!entry) {
throw new Error(
`SCAN: unknown cursor "${cursorArg}". Cluster-wide SCAN cursors are ` +
`minted per client instance and expire when idle — restart the scan from 0.`
);
}
return [{
client: await pinnedMaster(slots, entry.address),
parser: withCursor(parser, entry.cursor)
}];
};
const EMPTY_VISITED: ReadonlySet<string> = new Set();
View on GitHub (pinned to 90fd0652bc)