redis/node-redis · error · ClientOfflineError
The client is offline
Error message
The client is offline
What it means
Thrown from RedisClusterSlots.#assertReady (cluster-slots.ts:892) as ClientOfflineError when #isOpen is true but #isReady is false. The cluster is open but not yet ready to route commands — typically because initial discovery is still running, or readiness was lost (e.g. destroyed mid-discovery resets isReady) and not yet re-established. Any routing/command method gated by assertReady rejects.
Source
Thrown at packages/client/lib/cluster/cluster-slots.ts:892
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();
return [...this.masters, ...this.replicas];
}
/** Master fan-out target nodes, WITHOUT connecting (see {@link getAllNodes}). */View on GitHub (pinned to bb5beb5657)
Solutions
- Await cluster.connect() so #isReady is true before sending commands.
- Before bursts of commands, check cluster.isReady and back off / retry if false.
- For intermittent unready windows, retry the command with a short backoff.
Example fix
// before
cluster.connect(); // not awaited
await cluster.get('k'); // throws 'The client is offline'
// after
await cluster.connect();
await cluster.get('k'); Defensive patterns
Strategy: validation
Validate before calling
if (!cluster.isReady) { /* wait or back off */ } Type guard
import { ClientOfflineError } from '@redis/client';
function isClientOffline(e: unknown): boolean {
return e instanceof Error && (e instanceof ClientOfflineError || /client is offline/i.test(e.message));
} Try / catch
for (let i = 0; i < 5; i++) {
try { return await cluster.get('k'); }
catch (e) { if (isClientOffline(e) && i < 4) { await sleep(100 * 2 ** i); continue; } throw e; }
} Prevention
- Await connect() so isReady is true before traffic.
- Check cluster.isReady before bursts and back off if false.
- Retry with backoff through transient unready windows.
When it happens
Trigger: Issuing a command after connect() started but before it resolved (isReady still false); issuing a command during a reconnect/topology refresh window where isReady has dropped.
Common situations: Forgetting to await connect(); racing the first command; issuing commands during a transient unready window after a topology event.
Related errors
AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03).
Data as JSON: /data/errors/8ef074e5aee4405e.json.
Report an issue: GitHub.