Skip to content

[Bug]: DNS and network reachability failures incorrectly rotate Codex pool accounts #914

Description

@luvs01

Client or integration

Codex App

Area

Authentication and account pool

Summary

Pre-connection DNS and local network failures are currently recorded as failures of the selected Codex account. Regular Responses and native compact map every thrown non-timeout transport error to connect_error; after upstreamFailoverThreshold failures, OpenCodex soft-avoids that account, clears thread affinity, and changes the effective account.

This is incorrect for source-proven reachability failures such as ENOTFOUND, EAI_AGAIN, ENETUNREACH, ENETDOWN, EHOSTUNREACH, ECONNREFUSED, and equivalent bounded Bun error codes. Credential replacement cannot repair a machine-wide DNS or network outage, and concurrent agents can cross the default threshold almost immediately.

Expected behavior:

  • Return the existing client-visible 502, but classify proven pre-connection DNS/network reachability failures as account-neutral.
  • Do not increment account failure streak, set soft-avoid/cooldown, clear affinity, or change runtime/persisted active account.
  • Release any owned quota-probe lease without treating the failure as account evidence.
  • Inspect stable codes through a bounded cause chain; do not trust an unanchored message substring.
  • Preserve current handling for ECONNRESET, EPIPE, established-socket closure, TimeoutError, HTTP 5xx, actual 429/402, 401/403, and client cancellation.

Relevant source:

  • src/server/responses/core.ts: native passthrough transport failure recording.
  • src/server/responses/compact.ts: compact transport failure recording.
  • src/codex/routing.ts: transient streak, soft-avoid, affinity clear, and active failover.
  • src/lib/upstream-retry.ts: existing narrow transport classification.
  • src/codex/auth-context.ts: probe-lease release.

Required tests: table-driven bounded cause-chain classification; negative message-only cases; routing state unchanged after three neutral failures; regular and compact end-to-end ENOTFOUND cases; concurrent neutral failures; and proof that an owned probe lease is released. Existing reset/socket/timeout/HTTP failover regressions must remain.

Related: #186/#194 (established-connection and transient recovery, which this must not undo), #714 (retry/amplification rather than account-state mutation), and #504/#506 (thresholded account failover).

Reproduction

  1. Configure at least two Codex pool accounts and bind a thread to account A.
  2. Keep the default upstreamFailoverThreshold: 3.
  3. Make the provider hostname unresolvable, or inject a pre-response error with stable code ENOTFOUND.
  4. Send three concurrent or sequential requests.
  5. Restore network reachability and inspect the next routing decision.

Current: A is soft-avoided, affinity can be cleared, and another account can become effective.

Expected: requests may return 502 during the outage, but A's health, affinity, and active-account state remain unchanged.

Version

2.10.0; the relevant transport branches remained on dev at 075c2f34c060d068ed56985e76924a9f23aca39d when checked on 2026-08-03.

Operating system

Windows 11 Pro 10.0.26200; equivalent Node/Bun shapes should be covered on every supported platform.

Provider and model

OpenAI (Codex login / forward account pool); native Codex models.

Logs or error output

Provider unreachable: getaddrinfo ENOTFOUND <provider-host>

Screenshots and supporting files

None. Hostnames, account identifiers, and request identifiers are removed.

Redacted configuration

{
  "providers": {
    "openai": {
      "adapter": "openai-responses",
      "authMode": "forward",
      "codexAccountMode": "pool"
    }
  },
  "accountPoolStrategy": "fill-first",
  "upstreamFailoverThreshold": 3,
  "activeCodexAccountId": "__main__"
}

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, plansbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions