Skip to content

fix: allow ioredis to resolve IPv6-only Redis endpoints (#15290) - #15309

Open
PiedPiper911 wants to merge 1 commit into
LibreChat-AI:devfrom
PiedPiper911:fix/redis-ipv6-family-15290
Open

PiedPiper911 wants to merge 1 commit into
LibreChat-AI:devfrom
PiedPiper911:fix/redis-ipv6-family-15290

Conversation

@PiedPiper911

Copy link
Copy Markdown

Summary

Fixes #15290 — ioredis defaults to IPv4 (family: 4), which breaks connections on IPv6 single-stack clusters (ENOTFOUND, no A record). Setting family: 0 on the shared ioredis options allows the resolver to try both address families: IPv4 first (unchanged behavior for existing users), IPv6 fallback for IPv6-only deployments.

Change Type

  • Bug fix (non-breaking change which fixes an issue)

Testing

  • family: 0 is the standard ioredis value to accept either address family (Node dns.lookup default behavior: IPv4 first, IPv6 fallback)
  • IPv4 users: unchanged (IPv4 resolution still works and is tried first)
  • IPv6-only: resolves via AAAA record instead of failing with ENOTFOUND
  • Applied to the shared redisOptions used by both single-node and cluster ioredis clients in redisClients.ts
  • Prettier (repo .prettierrc) passes

Test Configuration:

  • No behavioral change for IPv4 environments

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • I have commented in any complex areas of my code
  • I have made pertinent documentation changes
  • My changes do not introduce new warnings
  • I have written tests demonstrating that my changes are effective or that my feature works
  • Local unit tests pass with my changes
  • Any changes dependent on mine have been merged and published in downstream modules.
  • A pull request for updating the documentation has been submitted.

@danny-avila

Copy link
Copy Markdown
Collaborator

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: d394341a67

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@PiedPiper911

Copy link
Copy Markdown
Author

Hi @danny-avila — just following up on this PR (fix for #15290, IPv6-only Redis endpoints). The Codex review came back clean ("didn't find any major issues"), and the branch is up to date with main. Anything else you'd like changed before merge, or is it good to go? Happy to adjust if needed. Thanks!

@PiedPiper911

Copy link
Copy Markdown
Author

Heads up @danny-avila — the Cache Integration Tests failure (Redis Cluster step) was a bug in my own new test, not in the fix. 😅

Root cause: under the cluster CI step (USE_REDIS_CLUSTER=true), every module load creates an IoRedis.Cluster client, whose options nest family under redisOptions. My "single instance" address-family test asserted a top-level family on .options — which only holds for the standalone new IoRedis(...) branch — so it only passed in the single-node step by accident.

Fix (5e733fc1): the test now explicitly sets USE_REDIS_CLUSTER=false + the standalone REDIS_URI before importing the module, so it deterministically exercises the non-cluster branch in both CI steps (the cluster assertion already sets its own env). The actual family: 0 code change is untouched.

CI is re-running now — should go green on both the single-node and cluster steps.

@PiedPiper911

Copy link
Copy Markdown
Author

Small follow-up: the workflow runs on the new head (5e733fc1) are queued with action_required — they need a maintainer to approve them before they start (Cache Integration Tests among them). If you could approve when you get a chance, I'll confirm green across both the single-node and cluster steps.

@danny-avila danny-avila added the 🗺️ Concurrency Cache codegraph: the taxonomy area this belongs to (classifier, confidence ≥ 0.9) label Sep 24, 2026
@PiedPiper911
PiedPiper911 changed the base branch from main to dev September 25, 2026 01:54
@codegraph-librechat codegraph-librechat Bot added 🗺️ Backend Platform codegraph: the taxonomy area this belongs to (classifier, confidence ≥ 0.9) 🗺️ Cache & Storage codegraph: the taxonomy area this belongs to (classifier, confidence ≥ 0.9) 🗺️ Backend Infra codegraph: the taxonomy area this belongs to (classifier, confidence ≥ 0.9) labels Oct 1, 2026
…#15290)

Rebased onto current dev. `redisClients.ts` has been refactored on dev since
this branch was opened (heartbeat module, readonly-replica recovery, keyv
script routing), so this is a three-way merge rather than a replay: the
insertion is reapplied inside the current `redisOptions` object and the dev
refactor is preserved unchanged. The diff against dev is +11 lines, all
additions, in `redisClients.ts` and `experimental.js` — nothing removed.

ioredis defaults to `family: 4`. On an IPv6 single-stack cluster the Redis
hostname has no A record, so connections fail with ENOTFOUND before
authentication is even attempted. `family: 0` lets the resolver return
either family and lets Node's Happy Eyeballs (autoSelectFamily, default
since Node 20) pick, so dual-stack hosts may now connect over IPv6 too.

Applied to the single-instance options, the cluster `redisOptions`, and the
standalone `flush-cache.js` / `experimental.js` scripts.

Note on the previous head: the nine workflows that ran on 5e733fc on
Sep 2 all failed with zero jobs, i.e. they failed before any job started,
so those were never real test results. This head supersedes them.
@PiedPiper911
PiedPiper911 force-pushed the fix/redis-ipv6-family-15290 branch from 5e733fc to c2d02a0 Compare October 5, 2026 14:59
@PiedPiper911

Copy link
Copy Markdown
Author

Rebased onto current dev (c2d02a0ca124). Two things worth flagging, one of which changes how you should read this PR.

The nine red checks on the previous head were not test results. On 5e733fc1 (Sep 2) nine workflows all failed within the same minute — Static Checks, Backend Unit Tests, Cache Integration Tests, Playwright E2E, Docker Build Smoke, Agents Integration, Codegraph Select, Bombadil, Retarget PRs — and every one of them recorded zero jobs. A run that fails with no jobs never reached a single step, so none of those nine ran a test or a linter. They do not represent failures in this change. This head supersedes them; the checks will re-run from a current base.

redisClients.ts was refactored on dev since this branch was opened. It now has startRedisHeartbeat / isReadonlyReplicaError / createReadonlyRecovery / keyv script routing, and my original two-line insertion was written against the older file. A naive replay would have reverted that work, so this is a three-way merge: the insertion is reapplied inside the current redisOptions object and the refactor is untouched. The diff against dev is +36/-0 across all four files — nothing removed, which is the property to check if you want to confirm nothing was clobbered:

  • redisClients.ts +9
  • experimental.js +2
  • flush-cache.js +2
  • redisClients.cache_integration.spec.ts +23

I also checked whether dev had already solved this, and it has not. The dnsLookup now present in redisClients.ts is the REDIS_USE_ALTERNATIVE_DNS_LOOKUP passthrough (it returns the address unchanged); it is opt-in and does nothing for address-family selection. There is no family setting anywhere on dev, so the underlying bug from #15290 is still open.

What the fix is. ioredis defaults to family: 4. On an IPv6 single-stack cluster the Redis hostname has no A record, so the connection fails with ENOTFOUND before authentication is attempted. family: 0 accepts either family and lets Node resolve both records and connect via Happy Eyeballs (autoSelectFamily, default since Node 20), so dual-stack hosts may now use IPv6 as well. Applied to the single-instance options, the cluster redisOptions, and the two standalone scripts (flush-cache.js, experimental.js) so the same URI behaves consistently everywhere.

The integration spec asserts the option lands where each client type reads it — options.family for a single instance, options.redisOptions.family for a cluster — which is the part that broke on the earlier head.

One thing I cannot do from here: the workflows on this head will sit at action_required until a maintainer approves them, so the fresh runs need your click before they will report anything.

@codegraph-librechat codegraph-librechat Bot added the 🗺️ Platform Security codegraph: the taxonomy area this belongs to (classifier, confidence ≥ 0.9) label Oct 9, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🗺️ Backend Infra codegraph: the taxonomy area this belongs to (classifier, confidence ≥ 0.9) 🗺️ Backend Platform codegraph: the taxonomy area this belongs to (classifier, confidence ≥ 0.9) 🗺️ Cache & Storage codegraph: the taxonomy area this belongs to (classifier, confidence ≥ 0.9) 🗺️ Concurrency Cache codegraph: the taxonomy area this belongs to (classifier, confidence ≥ 0.9) 🗺️ Platform Security codegraph: the taxonomy area this belongs to (classifier, confidence ≥ 0.9)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: ioredis is IPv4 only, add IPv6 support

2 participants