`codex exec`/app-server fails with "failed to lookup address information: Try again" behind DNS middleboxes that answer `AAAA` with `REFUSED` — same environment works for curl/glibc tools
Environment
- codex-cli 0.137.0-alpha.4 (bundled
openai-codex-cli-bin0.137.0a4 /
openai-codex 0.1.0b3 Python SDK) — Linux x86_64 binary is
static-PIE (musl) per file(1)
- Guest: Debian trixie userland (glibc 2.41), Linux 6.12, inside a
microsandbox microVM whose DNS is a userspace interceptor
- Auth:
OPENAI_API_KEY(ApiKey mode)
Summary
The VM's DNS resolver has a real bug: for a name that has A records but noAAAA (api.openai.com), it answers the AAAA query with REFUSED
(rcode 5) instead of NOERROR+empty (NODATA). We've reported that separately to microsandbox: https://github.com/superradcompany/microsandbox/issues/1139
However, the impact asymmetry is worth a look on codex's side:
- glibc-linked tools tolerate it:
curl,getent, Python — and the
Anthropic/deepagents agents we run beside codex — all resolve
api.openai.com instantly (they use the A records; sequential and
40-thread-concurrent getaddrinfo loops: 0 failures in 200+ lookups).
- codex hard-fails: every turn dies after ~5 s with
stream disconnected before completion: failed to lookup address (wss:// first, then the HTTPS fallback), attempt
information: Try again
after attempt — the codex agent is unusable in this environment while
every other HTTP client on the box works.
RUST_LOG=debug shows the request never reaches TCP connect forapi.openai.com (no connecting to <ip>:443 afterreqwest::connect: starting new connection), while ab.chatgpt.com (which
HAS AAAA records, so no REFUSED is emitted) resolves and connects in ~3 ms
from the same process.
Since the Linux binary is statically linked (musl), codex doesn't get glibc's
lenient behavior of "use the A answer if the AAAA leg errors"; the resolver
in the static build appears to treat the REFUSED AAAA response as fatal for
the whole lookup (and retries against a secondary nameserver that may be
unreachable, burning the ~5 s budget).
Reproduction
Easiest faithful repro is a stub resolver that mimics the middlebox: answerA normally, answer AAAA for the target name with rcode 5.
- Run a local DNS proxy on 127.0.0.53 that forwards everything but rewrites
the AAAA api.openai.com response to REFUSED (a ~30-line Python UDP
proxy does it; happy to attach ours).
- Point
/etc/resolv.confat it. curl https://api.openai.com/v1/models→ fast 401 (works).OPENAI_API_KEY=… codex exec 'reply with: ok'→
failed to lookup address information: Try again after ~5 s, all retries.
Observed in the wild inside microsandbox VMs (their DNS interceptor behaves
exactly like the stub above).
Expected
codex's resolution should be no stricter than getaddrinfo(3) in practice: if
the A query succeeds, a failed/REFUSED AAAA leg should degrade to
IPv4-only resolution (arguably RFC 6555/8305 spirit), not fail the lookup —
matching what every glibc-linked client on the same host does.
Workaround (for anyone hitting this)
Pin the host's A records in /etc/hosts (codex consults it before
querying):
for ip in $(getent ahostsv4 api.openai.com | awk '{print $1}' | sort -u); do
echo "$ip api.openai.com" >> /etc/hosts
done
This restored codex end-to-end for us (thread.run → status=completed).
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗