redis/node-redis · critical · RootNodesUnavailableError
All the root nodes are unavailable
Error message
All the root nodes are unavailable
What it means
RootNodesUnavailableError, thrown at the end of #discoverWithRootNodes after every configured root node was tried and none returned a valid cluster topology. This means initial cluster connection (or a full rediscovery) could not reach any seed node. It surfaces as a typed error so callers can distinguish 'all roots down' from a single-node failure.
Solutions
- Verify each rootNode host/port is reachable from the client host (telnet/nc/redis-cli ping).
- Check network ACLs, security groups, and firewall rules permit TCP to the Redis ports.
- Confirm DNS resolves the rootNode hostnames and the IPs are current.
- Add redundant root nodes so a single unreachable seed does not cause total failure.
- Retry cluster.connect() after a backoff in case the outage is transient.
Example fix
// before
const cluster = createCluster({ rootNodes: [{ socket: { host: 'wrong-host', port: 6379 } }] });
await cluster.connect(); // RootNodesUnavailableError
// after
const cluster = createCluster({
rootNodes: [
{ socket: { host: 'redis-0.cluster', port: 6379 } },
{ socket: { host: 'redis-1.cluster', port: 6379 } }
]
});
await cluster.connect(); Defensive patterns
Strategy: retry
Validate before calling
async function canReachRoot(host: string, port: number): Promise<boolean> {
try {
const s = await new Promise<import('net').Socket>((res, rej) => {
const sock = require('net').connect(port, host, () => res(sock));
sock.on('error', rej);
});
s.destroy();
return true;
} catch { return false; }
} Type guard
function isRootNodesUnavailable(e: unknown): boolean {
return e instanceof RootNodesUnavailableError;
} Try / catch
for (let i = 0; i < 5; i++) {
try {
await cluster.connect();
break;
} catch (e) {
if (e instanceof RootNodesUnavailableError) { await new Promise(r => setTimeout(r, 1000 * (i + 1))); continue; }
throw e;
}
} Prevention
- Verify root node host/port reachability before connect().
- Configure multiple redundant root nodes.
- Check firewall/security-group rules permit TCP to Redis ports.
- Retry connect() with backoff for transient outages.
When it happens
Trigger: cluster.connect() where every entry in rootNodes is unreachable (wrong host/port, firewall, DNS failure, all nodes down). Also thrown on a full topology refresh if all roots are unreachable at that point.
Common situations: Misconfigured rootNodes host/port; Redis cluster behind a firewall/security group blocking the client; DNS not resolving cluster endpoints; all seed nodes temporarily down during a major outage; localhost vs 127.0.0.1 mismatch in containers.
Related errors
- Cluster already open
- Cluster closed
- Couldn't connect to any sentinel node
- None of the sentinels are available
- [Proxy] Failed to send SMIGRATED notification
AI-assisted analysis of redis/node-redis@90fd0652bc (2026-08-11).
Data as JSON: /api/errors/5eca4ef2a745ef16.
Report an issue: GitHub.
Appendix: source
Thrown at packages/client/lib/cluster/cluster-slots.ts:338
}
async #discoverWithRootNodes() {
const start = Math.floor(Math.random() * this.#options.rootNodes.length);
for (let i = start; i < this.#options.rootNodes.length; i++) {
if (!this.#isOpen) throw new Error('Cluster closed');
if (await this.#discover(this.#options.rootNodes[i])) {
return;
}
}
for (let i = 0; i < start; i++) {
if (!this.#isOpen) throw new Error('Cluster closed');
if (await this.#discover(this.#options.rootNodes[i])) {
return;
}
}
throw new RootNodesUnavailableError();
}
#resetSlots() {
this.slots = new Array(RedisClusterSlots.#SLOTS);
this.masters = [];
this.replicas = [];
this._randomNodeIterator = undefined;
}
async #discover(rootNode: RedisClusterClientOptions) {
this.clientSideCache?.clear();
this.clientSideCache?.disable();
try {
const addressesInUse = new Set<string>(),
promises: Array<Promise<unknown>> = [],
eagerConnect = this.#options.minimizeConnections !== true;
View on GitHub (pinned to 90fd0652bc)