redis/node-redis · critical · Error

None of the sentinels are available

Error message

None of the sentinels are available

What it means

`observe()` walks every sentinel root node trying to query the current master; if none of them can be reached (or all error out and get destroyed in the finally block), the loop exits and throws this terminal error. It is the Sentinel topology-discovery / failover-observation dead end.

Solutions

  1. Verify each `rootNodes` host:port is reachable (telnet/redis-cli ping).
  2. Check `sentinelClientOptions` auth (password) and TLS match the sentinels.
  3. Provide multiple sentinel seeds so one being down does not exhaust the list.
  4. Confirm network/DNS from the application host to the sentinel subnet.

Example fix

// before
rootNodes: [{ host: 'sentinel-primary', port: 26379 }]
// after
rootNodes: [
  { host: 'sentinel-1', port: 26379 },
  { host: 'sentinel-2', port: 26379 },
  { host: 'sentinel-3', port: 26379 }
]
Defensive patterns

Strategy: retry

Validate before calling

async function atLeastOneSentinelReachable(rootNodes: { host: string; port: number }[], opts?: { password?: string }): Promise<boolean> {
  for (const n of rootNodes) {
    const c = new RedisClient({ socket: { host: n.host, port: n.port }, password: opts?.password });
    try { await c.connect(); c.destroy(); return true; } catch { /* try next */ }
  }
  return false;
}

Try / catch

async function connectWithBackoff(sentinel: { connect(): Promise<void> }, attempts = 5) {
  for (let i = 0; i < attempts; i++) {
    try { await sentinel.connect(); return; }
    catch (e) {
      if (String(e).includes('None of the sentinels are available') && i < attempts - 1) {
        await new Promise(r => setTimeout(r, 500 * 2 ** i));
        continue;
      }
      throw e;
    }
  }
}

Prevention

When it happens

Trigger: All `rootNodes` sentinel endpoints unreachable during observe(); every sentinel client fails to connect or errors before returning master data. Surfaces from the internal connect/reset/scan loop, not a direct user call.

Common situations: Misconfigured or stale `rootNodes` (wrong host/port); network partition to the sentinel subnet; wrong `password`/TLS in `sentinelClientOptions`; all sentinel processes down; DNS resolution failure.

Related errors


AI-assisted analysis of redis/node-redis@90fd0652bc (2026-08-11). Data as JSON: /api/errors/bf050b9a23dc2f28. Report an issue: GitHub.

Appendix: source

Thrown at packages/client/lib/sentinel/index.ts:1364

          currentSentinel: this.getSentinelNode(),
          replicaPoolSize: this.#replicaPoolSize,
          useReplicas: this.useReplicas
        }

        return ret;
      } catch (err) {
        this.#trace(`observe: error ${err}`);
        this.emit('error', err);
      } finally {
        if (client !== undefined && client.isOpen) {
          this.#trace(`observe: destroying sentinel client`);
          client.destroy();
        }
      }
    }

    this.#trace(`observe: none of the sentinels are available`);
    throw new Error('None of the sentinels are available');
  }

  analyze(observed: Awaited<ReturnType<RedisSentinelInternal<M, F, S, RESP, TYPE_MAPPING>["observe"]>>) {
    let master = parseNode(observed.masterData);
    if (master === undefined) {
      this.#trace(`analyze: no valid master node because ${observed.masterData.flags}`);
      throw new Error("no valid master node");
    }

    if (master.host === observed.currentMaster?.host && master.port === observed.currentMaster?.port) {
      this.#trace(`analyze: master node hasn't changed from ${observed.currentMaster?.host}:${observed.currentMaster?.port}`);
      master = undefined;
    } else {
      this.#trace(`analyze: master node has changed to ${master.host}:${master.port} from ${observed.currentMaster?.host}:${observed.currentMaster?.port}`);
    }

    let sentinel: RedisNode | undefined = observed.sentinelConnected;
    if (sentinel.host === observed.currentSentinel?.host && sentinel.port === observed.currentSentinel.port) {

View on GitHub (pinned to 90fd0652bc)