Skip to content

fix: disable Happy Eyeballs for the zcode launch so slow-edge networks connect - #182

Open
camerontaylor wants to merge 1 commit into
william0wang:mainfrom
camerontaylor:fix/no-happy-eyeballs-timeout
Open

fix: disable Happy Eyeballs for the zcode launch so slow-edge networks connect#182
camerontaylor wants to merge 1 commit into
william0wang:mainfrom
camerontaylor:fix/no-happy-eyeballs-timeout

Conversation

@camerontaylor

Copy link
Copy Markdown

Problem

On networks without an IPv6 route where the model provider edge answers in just over 250ms, every model request from the spawned zcode app-server fails with:

Cannot connect to API:

(empty message — the cause is an AggregateError whose message is empty; the per-address codes live in .errors[]). Each request burns the full retry budget (~1.5s per attempt, 11 attempts) and the turn fails, while curl and plain net.connect to the same host succeed.

Root cause

Node enables autoSelectFamily (RFC 8305 Happy Eyeballs) by default since 20.13, with a 250ms per-attempt budget. zcode's model client goes through undici fetch, so:

  • IPv6 attempts fail instantly (EHOSTUNREACH, no route)
  • the IPv4 attempt needs ~270ms — just past the 250ms budget — and is aborted as ETIMEDOUT
  • all attempts exhausted → AggregateError → "Cannot connect to API:"

Reproduced on macOS with mise node 22.20 and 24.21 against api.z.ai:

$ node -e 'fetch("https://api.z.ai/").catch(e=>console.log(e.cause?.errors?.map(x=>x.code)))'
[ 'ETIMEDOUT', 'EHOSTUNREACH', 'ETIMEDOUT', 'EHOSTUNREACH' ]
$ curl -sS -o /dev/null -w '%{http_code} %{time_total}s' https://api.z.ai/
401 0.87s        # same machine, seconds later
$ node --no-network-family-autoselection -e 'fetch("https://api.z.ai/").then(r=>console.log(r.status))'
200

Fix

Pass --no-network-family-autoselection in the explicit-node launch path, restoring the pre-20.13 sequential connect (which succeeds — the route is fine, only the attempt budget is too tight). ZCODE_KEEP_HAPPY_EYEBALLS=1 opts out for networks that genuinely need RFC 8305 racing.

Note: this only covers the JS-bundle launch path where we build the argv. Wrapper-script bins (non-.js zcode) keep their own behavior — hosts in that situation can set NODE_OPTIONS=--no-network-family-autoselection for the daemon.

Verified end-to-end via the Paseo provider plugin: patched build completes model.request.completed → turn.completed where the unpatched build failed every request for 30 minutes.

🤖 Generated with Claude Code

…s connect

Node's autoSelectFamily (default since 20.13) gives each connect attempt a
250ms budget. On networks with no IPv6 route where the provider edge answers
in just over 250ms, every undici connect is aborted before establishing and
fetch fails with an empty-message AggregateError — model requests then fail
as 'Cannot connect to API:' on every retry, while curl and plain connects to
the same host succeed. Pass --no-network-family-autoselection to restore the
pre-20.13 sequential connect; ZCODE_KEEP_HAPPY_EYEBALLS=1 opts out.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant