redis/node-redis · error · ClientClosedError
The client is closed
Error message
The client is closed
What it means
Thrown by RedisClusterSlots.#assertReady() (invoked by getClientAndSlotNumber, getAllNodes, getAllMasterNodes, and every command route) when #isOpen is false. The cluster was never connected, or was disconnected/destroyed, so there is no slot map and no node clients to route a command to.
Solutions
- Call and await cluster.connect() before issuing any command.
- Guard command-issuing code with if (cluster.isOpen).
- Do not issue commands after disconnect()/destroy(); re-connect first if needed.
- Centralize cluster lifecycle so command code only runs after connect() resolves.
Example fix
// before
const cluster = createCluster({ rootNodes });
await cluster.set('k', 'v'); // throws ClientClosedError (never connected)
// after
const cluster = createCluster({ rootNodes });
await cluster.connect();
await cluster.set('k', 'v'); Defensive patterns
Strategy: validation
Validate before calling
if (!cluster.isOpen) {
throw new Error('Cluster is not open. Call await cluster.connect() first.');
} Type guard
function clusterIsOpen(cluster: RedisClusterType): boolean {
return cluster.isOpen;
} Try / catch
try {
await cluster.set('k', 'v');
} catch (e) {
if (e instanceof ClientClosedError) {
await cluster.connect();
await cluster.set('k', 'v');
} else throw e;
} Prevention
- Always await cluster.connect() before issuing commands.
- Guard command code with if (cluster.isOpen).
- Do not issue commands after disconnect()/destroy().
When it happens
Trigger: Issuing any command (get, set, etc.) on a cluster before calling cluster.connect(). Issuing commands after cluster.disconnect() or cluster.destroy(). Issuing commands in a reconnect path before the cluster has re-opened.
Common situations: Forgetting to await cluster.connect() before first command; calling commands in a constructor that runs before bootstrap; issuing commands after a shutdown flag closed the cluster; test code running before the cluster is connected.
Related errors
- Cluster already open
- All the root nodes are unavailable
- Cluster closed
- FT.CURSOR: unknown cursor
- Socket already opened
AI-assisted analysis of redis/node-redis@90fd0652bc (2026-08-11).
Data as JSON: /api/errors/01b6bbdac056a27a.
Report an issue: GitHub.
Appendix: source
Thrown at packages/client/lib/cluster/cluster-slots.ts:991
promises.push(fn(client));
}
if (this.pubSubNode) {
promises.push(fn(this.pubSubNode.client));
this.pubSubNode = undefined;
}
this.#resetSlots();
this.nodeByAddress.clear();
this.#reconnectionTracker.clear();
await Promise.allSettled(promises);
this.#emit('disconnect');
}
#assertReady() {
if (!this.#isOpen) {
throw new ClientClosedError();
}
if (!this.#isReady) {
throw new ClientOfflineError();
}
}
/**
* All fan-out target nodes (masters + replicas), WITHOUT connecting. The
* caller connects each node lazily in its own per-node promise so a single
* failed connect rejects only that node's execution — letting reducers such
* as `one_succeeded` still see the reachable shards — instead of a `Promise.all`
* over the connects failing the whole route up front. Excludes the dedicated
* PubSub connection (not in `masters`/`replicas`).
*/
getAllNodes() {
this.#assertReady();
View on GitHub (pinned to 90fd0652bc)