redis/node-redis · error · ClientClosedError
The client is closed
Error message
The client is closed
What it means
Thrown from RedisClusterSlots.#assertReady (cluster-slots.ts:888) as ClientClosedError when #isOpen is false. assertReady guards every routing method (getAllNodes, getClientForKey, getClientAndSlotNumber, scan, etc.), so any command issued against a cluster that has been closed/destroyed (or never connected) rejects with this.
Source
Thrown at packages/client/lib/cluster/cluster-slots.ts:888
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 bb5beb5657)
Solutions
- Ensure cluster.connect() has resolved before issuing commands (await it at startup).
- Do not issue commands after close()/destroy(); gate them on cluster.isOpen.
- On fatal errors, recreate the cluster rather than reusing a closed instance.
Example fix
// before
const cluster = createCluster({ rootNodes });
await cluster.set('k', 'v'); // throws 'The client is closed' — 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 not open — call connect() first'); } Type guard
import { ClientClosedError } from '@redis/client';
function isClientClosed(e: unknown): boolean {
return e instanceof Error && (e instanceof ClientClosedError || /client is closed/i.test(e.message));
} Prevention
- Await cluster.connect() before issuing any command.
- Stop sending commands after close()/destroy().
- Recreate the cluster after a fatal close rather than reusing it.
When it happens
Trigger: Issuing a command after cluster.close()/destroy(); issuing a command before connect() resolved; issuing commands during shutdown after the cluster was closed.
Common situations: Missing await cluster.connect() at startup; using the cluster after an error handler closed it; shutdown sequence that closes first then drains queued work.
Related errors
AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03).
Data as JSON: /data/errors/01b6bbdac056a27a.json.
Report an issue: GitHub.