No supported configuration path for DNS: settings.json `env` is applied after Bun runtime init
Summary
Claude Code now ships as a Bun-compiled standalone binary, so it inherits Bun's DNS behaviour.
When that behaviour is wrong for a given network — split-DNS, VPN, corporate internal zones,
cluster DNS — there is no supported configuration path to correct it, because the only
available lever is an environment variable read at Bun runtime init, and settings.json'senv block is applied after that point.
This is a configuration-surface gap, filed separately from the underlying resolver bug
(reported upstream as oven-sh/bun#40573).
Environment
- Claude Code 2.1.246 (also reproduced on 2.1.245, 2.1.241, 2.1.236)
- macOS 15 (Darwin 25.6.0), arm64
- Installed payload is a Bun-compiled Mach-O binary (
strings→Bun v1.4.1,
node/v26.3 compat shim), not a Node package
Observed symptom
On a host where an internal zone is served by a macOS supplemental/scoped SystemConfiguration
resolver, every HTTP MCP server on that zone fails, while stdio servers are fine:
$ claude mcp list
server-a: https://a.internal.example/mcp (HTTP) - ✘ Failed to connect — ENOTFOUND: getaddrinfo ENOTFOUND a.internal.example
server-b: https://b.internal.example/mcp (HTTP) - ✘ Failed to connect — ENOTFOUND: getaddrinfo ENOTFOUND b.internal.example
local-stdio-server: /usr/local/bin/some-server - ✔ Connected
Every other DNS client on the same machine, in the same shell, resolves those names correctly
(dscacheutil, dig, Python socket.getaddrinfo, Node 22.22.2).
The configuration gap
1. Nothing in the configuration surface covers DNS. Enumerating the binary's env vars:
strings -a /path/to/claude | grep -oE '\b(CLAUDE_CODE|BUN|NODE)_[A-Z0-9_]{3,}' | sort -u
yields CLAUDE_CODE_CERT_STORE (CA trust) and CLAUDE_CODE_CLIENT_CERT (mTLS), but nothing
for name resolution.
2. The one lever that works cannot be set through settings.json. The undocumented Bun
flag BUN_FEATURE_FLAG_DISABLE_DNS_CACHE_LIBINFO=1 resolves the symptom — but only when it is
in the environment at process launch:
| how the variable is set | claude mcp list result |
|---|---|
| "BUN_FEATURE_FLAG_DISABLE_DNS_CACHE_LIBINFO": "1" in ~/.claude/settings.json env | ✘ all HTTP servers ENOTFOUND |
| BUN_FEATURE_FLAG_DISABLE_DNS_CACHE_LIBINFO=1 claude mcp list | ✔ all servers Connected |
Both rows were run back to back on the same machine and config, with the shell variable
explicitly unset for the first. The flag is read during Bun runtime init, before Claude Code
loads settings, so the settings layer can never influence it. This generalises: no runtime
startup flag is reachable from settings.json.
The practical consequence is that an affected user has no supported fix. The working workaround
is to export the variable from a shell profile before launching, which is outside anything
Claude Code documents or manages, and is invisible to /doctor.
Request
Either:
- apply
settings.json'senvblock early enough to influence runtime init (or provide a
documented pre-init env layer for exactly this class of variable); or
- expose a documented DNS/resolver setting.
Even a /doctor check that reports "hostname resolves via system resolver but not via the
Claude Code runtime" would turn a multi-session dead end into a one-line diagnosis.
Honest caveat
On the reporting machine the DNS symptom later cleared on its own after an unrelated local
resolver event, and Claude Code no longer reproduces it there. The upstream Bun regression is
still reproducible standalone (oven-sh/bun#40573). The settings.json-cannot-reach-runtime-init
finding above is independent of the DNS symptom and was verified directly while it reproduced.
Hostnames sanitised.