{"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/bb5beb56578573910e2ee8f39681edc214c41398/packages/client/lib/sentinel/index.ts#L1346-L1382","documentation":"Thrown by observe() after iterating every node in #sentinelRootNodes and failing to connect (or failing the SENTINEL SENTINELS/MASTER/REPLICAS queries) on all of them (sentinel/index.ts:1363). observe() is the discovery phase of connect()/reconfigure; if no sentinel can be reached, there is no topology to act on and the error propagates up through #connect()'s retry loop (bounded by maxCommandRediscovers) to the public connect().","triggerScenarios":"Calling connect() (or triggering a background reconfigure) when all seed/discovered sentinel nodes are unreachable: wrong host/port, network partition, firewall, DNS failure, or sentinel auth (requirepass) mismatch in sentinelClientOptions.","commonSituations":"Initial connect in an environment where the sentinel hostnames resolve but ports are blocked; TLS misconfig; sentinelClientOptions missing the password for a sentinel that enforces requirepass; all sentinels down during a cluster-wide outage.","solutions":["Verify each sentinelRootNodes entry is reachable: `redis-cli -h <host> -p <port> PING`.","Check sentinelClientOptions credentials/TLS match the sentinel's requirepass/TLS settings.","Confirm DNS resolution and firewall rules for the sentinel ports (default 26379) from the client host.","Listen for the 'error' event (emitted per failed sentinel in observe) to see the underlying socket error."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Pre-flight: can we reach any sentinel at all?\nimport net from 'node:net';\nasync function anySentinelReachable(nodes) {\n  for (const { host, port } of nodes) {\n    if (await new Promise(res => {\n      const s = net.connect({ host, port: Number(port) });\n      s.once('connect', () => { s.destroy(); res(true); });\n      s.once('error', () => res(false));\n      setTimeout(() => { s.destroy(); res(false); }, 1000);\n    })) return true;\n  }\n  return false;\n}\nif (!(await anySentinelReachable(options.sentinelRootNodes))) {\n  throw new Error('no sentinel seed reachable — refusing to call connect()');\n}","typeGuard":null,"tryCatchPattern":"async function connectWithRetry(sentinel, attempts = 5) {\n  for (let i = 0; i < attempts; i++) {\n    try {\n      await sentinel.connect();\n      return;\n    } catch (e) {\n      if (e instanceof Error && /None of the sentinels are available/.test(e.message) && i < attempts - 1) {\n        await new Promise(r => setTimeout(r, 1000 * (i + 1)));\n        continue;\n      }\n      throw e;\n    }\n  }\n}","preventionTips":["Run a reachability check (PING) on each sentinel seed before connecting.","Verify sentinelClientOptions auth/TLS match the sentinels' requirepass/TLS.","Provide multiple sentinel seeds across hosts/AZs.","Attach an 'error' listener to capture per-node socket errors during observe."],"tags":["network","sentinel","connectivity","discovery"],"analyzedSha":"bb5beb56578573910e2ee8f39681edc214c41398","analyzedAt":"2026-08-03T19:09:15.686Z","schemaVersion":2}