{"record":{"id":"23cec5d3c4b74a67","repo":"redis/node-redis","slug":"no-available-replicas","errorCode":null,"errorMessage":"no available replicas","messagePattern":"no available replicas","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/client/lib/sentinel/index.ts","lineNumber":1827,"sourceCode":"        }\n\n        return replicas;\n      } finally {\n        client.destroy();\n      }\n    }\n\n    if (connected) {\n      throw new Error(\"No Replicas Nodes Enumerated\");\n    }\n\n    throw new Error(\"couldn't connect to any sentinels\");\n  }\n\n  async getReplicaClient() {\n    const replicas = await this.getReplicaNodes();\n    if (replicas.length == 0) {\n      throw new Error(\"no available replicas\");\n    }\n\n    this.#replicaIdx++;\n    if (this.#replicaIdx >= replicas.length) {\n      this.#replicaIdx = 0;\n    }\n\n    const replica = replicas[this.#replicaIdx];\n    const socket = getMappedNode(replica.host, replica.port, this.options.nodeAddressMap);\n    return RedisClient.create({\n      ...this.options.nodeClientOptions,\n      socket: {\n        ...this.options.nodeClientOptions?.socket,\n        host: socket.host,\n        port: socket.port\n      }\n    });\n  }","sourceCodeStart":1809,"sourceCodeEnd":1845,"githubUrl":"https://github.com/redis/node-redis/blob/90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58/packages/client/lib/sentinel/index.ts#L1809-L1845","documentation":"`getReplicaClient()` calls `getReplicaNodes()` and then defensively re-checks `replicas.length == 0`, throwing 'no available replicas'. Normally [90]/[91] already throw inside getReplicaNodes; this guard catches the edge where an empty list is returned without an earlier throw, so a replica client is never built against nothing.","triggerScenarios":"Reaching `getReplicaClient()` after `getReplicaNodes()` returned an empty array (the rare path that bypasses the inner throws).","commonSituations":"Race where topology changed between enumeration and client creation; future code paths that short-circuit getReplicaNodes; defensive duplicate of the no-replicas condition.","solutions":["Ensure the topology has healthy replicas before requesting a replica client.","Set `replicaPoolSize` > 0 and confirm replicas are enumerated.","Fall back to a master client when replicas are unavailable."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"async function replicasExist(sentinel: { getReplicaNodes(): Promise<unknown[]> }): Promise<boolean> {\n  try { return (await sentinel.getReplicaNodes()).length > 0; }\n  catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try { return await sentinel.getReplicaClient(); }\ncatch (e) {\n  if (String(e).includes('no available replicas')) {\n    return await sentinel.getMasterClient();\n  }\n  throw e;\n}","preventionTips":["Gate replica reads on a replicas-exist check.","Design read paths to fall back to master during replica gaps."],"tags":["sentinel","replicas","read-routing","defensive"],"backgroundTag":null,"analyzedSha":"90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58","analyzedAt":"2026-08-11T15:37:21.243Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}