hermes - ✅(Solved) Fix httpx.Client missing retry transport causes auth failures when provider DNS resolves to multiple IPs (first IP refused) [2 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#28500Fetched 2026-05-20 04:03:34
View on GitHub
Comments
0
Participants
1
Timeline
6
Reactions
0
Participants
Timeline (top)
labeled ×4cross-referenced ×2

hermes auth fails with ConnectError: [Errno 61] Connection refused for providers whose DNS resolves to multiple IPs when the first IP actively refuses connections. httpx.Client instances in auth.py are created without a retry transport, so httpx dies on the first refused IP and never attempts the fallback.

Root Cause

All httpx.Client(...) instantiations in hermes_cli/auth.py lack a transport= parameter. The default httpcore connection pool does not retry on a different IP when the first connection is refused (errno 61).

This is distinct from a general network failure — curl succeeds because it tries all resolved IPs sequentially.

Fix Action

Fix

Apply retry transport to all httpx.Client instantiations in auth.py:

sed -i '' 's/httpx\.Client(/httpx.Client(transport=httpx.HTTPTransport(retries=3), /g' hermes_cli/auth.py

Or manually add transport=httpx.HTTPTransport(retries=3) to each httpx.Client( call. The bare httpx.post() / httpx.get() module-level calls should similarly be replaced with a client that has retry transport.

Workaround

Manually patch hermes_cli/auth.py as above. Note: patch is overwritten on hermes update.

PR fix notes

PR #28545: Retry auth HTTP connections across resolved IPs

Description (problem / solution / changelog)

Summary

  • route auth HTTP client creation through a shared retry-enabled transport
  • apply the retry path to auth flows that were still using one-shot httpx requests
  • add regression coverage for Codex token refresh and xAI discovery

Closes #28500

Testing

  • git diff --check
  • uv run --frozen ruff check hermes_cli/auth.py tests/hermes_cli/test_auth_http_retries.py tests/hermes_cli/test_auth_xai_oauth_provider.py
  • ./.venv/bin/python -m pytest -o addopts= tests/hermes_cli/test_auth_http_retries.py tests/hermes_cli/test_auth_codex_provider.py tests/hermes_cli/test_auth_xai_oauth_provider.py -q

Changed files

  • hermes_cli/auth.py (modified, +51/-18)
  • tests/hermes_cli/test_auth_http_retries.py (added, +96/-0)
  • tests/hermes_cli/test_auth_xai_oauth_provider.py (modified, +6/-6)

PR #28573: fix(auth): add retry transport to httpx.Client for DNS multi-IP fallback

Description (problem / solution / changelog)

Problem

When a hostname resolves to multiple IPs (e.g. portal.nousresearch.com76.76.21.61 + 66.33.60.130), httpcore's default connection pool tries only the first IP. If that IP refuses the connection (errno 61), the request fails immediately with no fallback to the second IP.

This causes intermittent auth failures, especially on:

  • Nous Portal token refresh
  • Codex OAuth device code flow
  • xAI OAuth discovery
  • MiniMax OAuth flows

Fix

Add transport=httpx.HTTPTransport(retries=3) to all httpx.Client() calls in hermes_cli/auth.py. With retries=3, httpcore retries on the next resolved IP.

Module-level constant for calls without verify:

_RETRY_TRANSPORT = httpx.HTTPTransport(retries=3)

Inline transport for calls with verify=verify:

transport=httpx.HTTPTransport(retries=3, verify=verify)

Changes

  • 12 httpx.Client() calls updated in hermes_cli/auth.py
  • 6 calls use _RETRY_TRANSPORT (no custom verify)
  • 6 calls use inline httpx.HTTPTransport(retries=3, verify=verify)

Testing

  • Verified httpx.HTTPTransport(retries=3) is a valid httpx API (no new dependencies)
  • The transport parameter is compatible with all existing httpx.Client options
  • No behavioral change when DNS returns a single IP (retries are cheap no-ops)

Fixes #28500

Changed files

  • hermes_cli/auth.py (modified, +15/-12)

Code Example

import httpx

# Fails — no retry, hits first IP and dies
r = httpx.post('https://portal.nousresearch.com/api/oauth/device/code', timeout=15)

# Works — retries on second IP
with httpx.Client(transport=httpx.HTTPTransport(retries=3)) as c:
    r = c.post('https://portal.nousresearch.com/api/oauth/device/code', timeout=15)
    print(r.status_code)  # 400 (valid server response, portal is reachable)

---

sed -i '' 's/httpx\.Client(/httpx.Client(transport=httpx.HTTPTransport(retries=3), /g' hermes_cli/auth.py
RAW_BUFFERClick to expand / collapse

Bug Report

Summary

hermes auth fails with ConnectError: [Errno 61] Connection refused for providers whose DNS resolves to multiple IPs when the first IP actively refuses connections. httpx.Client instances in auth.py are created without a retry transport, so httpx dies on the first refused IP and never attempts the fallback.

Affected providers confirmed

  • nousportal.nousresearch.com resolves to 76.76.21.61 (refused) and 66.33.60.130 (works)
  • xai-oauth — intermittently affects OIDC discovery endpoint

Environment

  • macOS 26 (Tahoe)
  • Hermes v0.10.x
  • Python 3.11 (Homebrew)
  • httpx 0.28.1 / httpcore 1.0.9

Steps to reproduce

  1. Run hermes auth
  2. Select nous → OAuth → attempt to add or refresh credentials
  3. Auth fails immediately with ConnectError: [Errno 61] Connection refused

Verify the issue is IP-retry related:

import httpx

# Fails — no retry, hits first IP and dies
r = httpx.post('https://portal.nousresearch.com/api/oauth/device/code', timeout=15)

# Works — retries on second IP
with httpx.Client(transport=httpx.HTTPTransport(retries=3)) as c:
    r = c.post('https://portal.nousresearch.com/api/oauth/device/code', timeout=15)
    print(r.status_code)  # 400 (valid server response, portal is reachable)

Root cause

All httpx.Client(...) instantiations in hermes_cli/auth.py lack a transport= parameter. The default httpcore connection pool does not retry on a different IP when the first connection is refused (errno 61).

This is distinct from a general network failure — curl succeeds because it tries all resolved IPs sequentially.

Fix

Apply retry transport to all httpx.Client instantiations in auth.py:

sed -i '' 's/httpx\.Client(/httpx.Client(transport=httpx.HTTPTransport(retries=3), /g' hermes_cli/auth.py

Or manually add transport=httpx.HTTPTransport(retries=3) to each httpx.Client( call. The bare httpx.post() / httpx.get() module-level calls should similarly be replaced with a client that has retry transport.

Expected behavior

Auth completes successfully when at least one resolved IP is reachable.

Actual behavior

Auth fails on the first refused IP with no fallback, even when additional valid IPs are available in the DNS response.

Workaround

Manually patch hermes_cli/auth.py as above. Note: patch is overwritten on hermes update.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Auth completes successfully when at least one resolved IP is reachable.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix httpx.Client missing retry transport causes auth failures when provider DNS resolves to multiple IPs (first IP refused) [2 pull requests, 1 participants]