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.

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