{"record":{"id":"bf050b9a23dc2f28","repo":"redis/node-redis","slug":"none-of-the-sentinels-are-available","errorCode":null,"errorMessage":"None of the sentinels are available","messagePattern":"None of the sentinels are available","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/client/lib/sentinel/index.ts","lineNumber":1364,"sourceCode":"          currentSentinel: this.getSentinelNode(),\n          replicaPoolSize: this.#replicaPoolSize,\n          useReplicas: this.useReplicas\n        }\n\n        return ret;\n      } catch (err) {\n        this.#trace(`observe: error ${err}`);\n        this.emit('error', err);\n      } finally {\n        if (client !== undefined && client.isOpen) {\n          this.#trace(`observe: destroying sentinel client`);\n          client.destroy();\n        }\n      }\n    }\n\n    this.#trace(`observe: none of the sentinels are available`);\n    throw new Error('None of the sentinels are available');\n  }\n\n  analyze(observed: Awaited<ReturnType<RedisSentinelInternal<M, F, S, RESP, TYPE_MAPPING>[\"observe\"]>>) {\n    let master = parseNode(observed.masterData);\n    if (master === undefined) {\n      this.#trace(`analyze: no valid master node because ${observed.masterData.flags}`);\n      throw new Error(\"no valid master node\");\n    }\n\n    if (master.host === observed.currentMaster?.host && master.port === observed.currentMaster?.port) {\n      this.#trace(`analyze: master node hasn't changed from ${observed.currentMaster?.host}:${observed.currentMaster?.port}`);\n      master = undefined;\n    } else {\n      this.#trace(`analyze: master node has changed to ${master.host}:${master.port} from ${observed.currentMaster?.host}:${observed.currentMaster?.port}`);\n    }\n\n    let sentinel: RedisNode | undefined = observed.sentinelConnected;\n    if (sentinel.host === observed.currentSentinel?.host && sentinel.port === observed.currentSentinel.port) {","sourceCodeStart":1346,"sourceCodeEnd":1382,"githubUrl":"https://github.com/redis/node-redis/blob/90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58/packages/client/lib/sentinel/index.ts#L1346-L1382","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify each `rootNodes` host:port is reachable (telnet/redis-cli ping).","Check `sentinelClientOptions` auth (password) and TLS match the sentinels.","Provide multiple sentinel seeds so one being down does not exhaust the list.","Confirm network/DNS from the application host to the sentinel subnet."],"exampleFix":"// before\nrootNodes: [{ host: 'sentinel-primary', port: 26379 }]\n// after\nrootNodes: [\n  { host: 'sentinel-1', port: 26379 },\n  { host: 'sentinel-2', port: 26379 },\n  { host: 'sentinel-3', port: 26379 }\n]","handlingStrategy":"retry","validationCode":"async function atLeastOneSentinelReachable(rootNodes: { host: string; port: number }[], opts?: { password?: string }): Promise<boolean> {\n  for (const n of rootNodes) {\n    const c = new RedisClient({ socket: { host: n.host, port: n.port }, password: opts?.password });\n    try { await c.connect(); c.destroy(); return true; } catch { /* try next */ }\n  }\n  return false;\n}","typeGuard":null,"tryCatchPattern":"async function connectWithBackoff(sentinel: { connect(): Promise<void> }, attempts = 5) {\n  for (let i = 0; i < attempts; i++) {\n    try { await sentinel.connect(); return; }\n    catch (e) {\n      if (String(e).includes('None of the sentinels are available') && i < attempts - 1) {\n        await new Promise(r => setTimeout(r, 500 * 2 ** i));\n        continue;\n      }\n      throw e;\n    }\n  }\n}","preventionTips":["Provide multiple sentinel seeds so one outage does not exhaust discovery.","Pre-flight ping a sentinel before app boot.","Monitor sentinel reachability and surface it to ops."],"tags":["sentinel","network","connectivity","discovery","failover"],"backgroundTag":null,"analyzedSha":"90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58","analyzedAt":"2026-08-11T15:37:21.243Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}