Skip to content
Latchkey

Node.js "TypeError: fetch failed" (undici) in CI

Node's global fetch (powered by undici) wraps low-level failures in a terse TypeError: fetch failed. The real reason is in the cause chain - usually a transient DNS, connection, or TLS problem.

What this error means

A request made with the built-in fetch rejects with TypeError: fetch failed. The same call works locally and often passes when the job is retried, pointing at a flaky network rather than a code bug.

node
TypeError: fetch failed
    at node:internal/deps/undici/undici:13392:13
  cause: Error: connect ECONNREFUSED 127.0.0.1:443
    code: 'ECONNREFUSED'

Common causes

Transient network or DNS failure

A dropped connection, slow DNS, or a momentary registry/API blip surfaces as fetch failed. These are intermittent and pass on retry.

A service or proxy not reachable from the runner

The target host is firewalled, the proxy env is missing, or a local server under test is not up yet, so the connection is refused.

How to fix it

Inspect err.cause and retry transient failures

Log err.cause to see the underlying code, then wrap the request in a bounded retry for transient classes.

src/http.js
try {
  const res = await fetch(url);
} catch (err) {
  console.error('fetch failed cause:', err.cause);
  throw err;
}

Ensure the dependency is reachable

Confirm DNS/proxy settings and that any local service the test calls is started before the request runs.

  1. Check HTTP(S)_PROXY/NO_PROXY env in the runner.
  2. Wait for local servers to be ready before issuing requests.
  3. Verify the host resolves and is allowlisted from the runner.

How to prevent it

  • Always read err.cause to classify the underlying failure.
  • Add bounded retries around outbound calls for genuinely transient classes.
  • Wait for dependent services to be ready before making requests.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →