{"id":"4b4c5d63792030d1","repo":"redis/node-redis","slug":"couldn-t-connect-to-any-sentinel-node","errorCode":null,"errorMessage":"Couldn't connect to any sentinel node","messagePattern":"Couldn't connect to any sentinel node","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/client/lib/sentinel/index.ts","lineNumber":1714,"sourceCode":"      try {\n        await client.connect();\n      } catch {\n        if (client.isOpen) {\n          client.destroy();\n        }\n        continue;\n      }\n\n      try {\n        const sentinelData = await client.sentinel.sentinelSentinels(this.options.name);\n        this.#sentinelRootNodes = [node].concat(createNodeList(sentinelData));\n        return;\n      } finally {\n        client.destroy();\n      }\n    }\n\n    throw new Error(\"Couldn't connect to any sentinel node\");\n  }\n\n  async getMasterNode() {\n    let connected = false;\n\n    for (const node of this.#sentinelRootNodes) {\n      const client = RedisClient.create({\n        ...this.options.sentinelClientOptions,\n        socket: {\n          ...this.options.sentinelClientOptions?.socket,\n          host: node.host,\n          port: node.port,\n          reconnectStrategy: false\n        },\n        modules: RedisSentinelModule\n      }).on('error', err => this.emit(`getMasterNode: ${err}`));\n\n      try {","sourceCodeStart":1696,"sourceCodeEnd":1732,"githubUrl":"https://github.com/redis/node-redis/blob/bb5beb56578573910e2ee8f39681edc214c41398/packages/client/lib/sentinel/index.ts#L1696-L1732","documentation":"Thrown by RedisSentinelFactory.updateSentinelRootNodes() after iterating this.#sentinelRootNodes and failing client.connect() on every one (sentinel/index.ts:1713). Unlike the internal observe path, this is a user-facing factory method that refreshes the seed-node list by asking one reachable sentinel for its peers; if none can be dialed it gives up.","triggerScenarios":"Calling factory.updateSentinelRootNodes() when all configured sentinel seed nodes are unreachable or reject the connection.","commonSituations":"Refresh triggered after a network blip or during a full sentinel outage; wrong seed host/port in RedisSentinelFactory options; sentinelClientOptions auth wrong so every connect() throws.","solutions":["Verify each sentinelRootNodes host:port is dialable from the client (`redis-cli ... PING`).","Correct sentinelClientOptions (password/TLS) so connect() succeeds against the sentinels.","Add more redundant sentinel seeds so one is likely to be up.","Catch the rejection and retry with backoff rather than treating it as fatal."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Reuse the same reachability helper as error 83 before calling updateSentinelRootNodes().\nif (!(await anySentinelReachable(factory.options.sentinelRootNodes))) {\n  throw new Error('no sentinel seed reachable — skipping updateSentinelRootNodes()');\n}","typeGuard":null,"tryCatchPattern":"async function refreshRoots(factory, attempts = 3) {\n  for (let i = 0; i < attempts; i++) {\n    try {\n      await factory.updateSentinelRootNodes();\n      return;\n    } catch (e) {\n      if (e instanceof Error && /Couldn't connect to any sentinel node/.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":["Verify sentinel seed reachability before refreshing roots.","Keep redundant seeds so one is likely up.","Catch and retry with backoff; treat updateSentinelRootNodes as best-effort."],"tags":["network","sentinel","connectivity","factory"],"analyzedSha":"bb5beb56578573910e2ee8f39681edc214c41398","analyzedAt":"2026-08-03T19:09:15.686Z","schemaVersion":2}