denoland/deno · error · TypeError
fetch failed
Error message
fetch failed
What it means
The generic TypeError raised when the underlying Rust HTTP transport (reqwest) fails before or while establishing communication: DNS resolution errors, refused connections, TLS handshake failures, or broken pipes. It mirrors Node's undici shape: the TypeError itself says only 'fetch failed' and the real transport detail is nested in error.cause (an Error built from the Rust error string).
Source
Thrown at ext/fetch/26_fetch.js:595
if (cancelHandleRid !== null) {
core.tryClose(cancelHandleRid);
}
}
// Re-throw any body errors
if (resp.error !== null) {
if (inspectorRequestId !== null) {
safeEmit(inspectorNetwork.loadingFailed, {
requestId: inspectorRequestId,
timestamp: DateNow() / 1000,
type: "Fetch",
errorText: resp.error[0],
});
}
// `resp.error` is `[detail, cause]`, where `detail` is the full reqwest
// message and `cause` is the underlying transport error detail. Mirror
// Node's shape: `TypeError: "fetch failed"` with the detail in `.cause`.
const cause = resp.error[1];
throw new TypeError("fetch failed", { cause: new Error(cause) });
}
if (terminator.aborted) {
// op_fetch_send resolved successfully, so the FetchResponseResource is already in
// the resource table. The success path below either closes resp.responseRid
// (redirect / null-body / HEAD / CONNECT) or hands it to createResponseBodyStream,
// which owns its lifecycle. Only this aborted-after-resolve branch needs to close
// the rid manually, otherwise it leaks and trips the test sanitizer.
core.tryClose(resp.responseRid);
return abortedNetworkError();
}
processUrlList(req.urlList, req.urlListProcessed);
/** @type {InnerResponse} */
const response = {
headerList: resp.headers,
status: resp.status,
body: null,View on GitHub (pinned to 89f33cbef2)
Solutions
- Inspect err.cause.message for the actual transport error before changing anything
- Verify the exact host/port is reachable: curl the same URL from the same machine
- Fix the environment: start the target server, correct DNS/hosts, or configure proxy variables
- For self-signed/custom CAs pass --cert or set DENO_CERT; avoid blanket --unsafely-ignore-certificate-errors in production
- Add retry with exponential backoff for genuinely transient failures (ECONNRESET, timeouts)
Example fix
// before
const res = await fetch("https://api.example.com/data"); // TypeError: fetch failed
// after
try {
const res = await fetch("https://api.example.com/data");
} catch (err) {
console.error("transport error:", err.cause?.message);
} Defensive patterns
Strategy: retry
Validate before calling
async function reachable(url, timeoutMs = 3000) {
const ctl = new AbortController();
const t = setTimeout(() => ctl.abort(), timeoutMs);
try {
await fetch(url, { signal: ctl.signal });
return true;
} catch {
return false;
} finally {
clearTimeout(t);
}
} Type guard
function isFetchFailed(err: unknown): err is TypeError {
return err instanceof TypeError && err.message === "fetch failed";
} Try / catch
async function fetchWithRetry(url, init, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try {
return await fetch(url, init);
} catch (err) {
const transient = err instanceof TypeError && err.message === "fetch failed" &&
/timed out|connection reset|incomplete/i.test(String(err.cause?.message ?? ""));
if (!transient || i === attempts - 1) {
throw new Error(`fetch failed: ${err.cause?.message ?? err.message}`, { cause: err });
}
await new Promise((r) => setTimeout(r, 2 ** i * 250));
}
}
} Prevention
- Always log err.cause, not just the TypeError, to see the real transport error
- Smoke-test target host/port with curl from the same environment before debugging code
- Configure proxy env vars (HTTP_PROXY/HTTPS_PROXY/NO_PROXY) and CA certs (DENO_CERT) explicitly in CI
- Use AbortController timeouts so hangs surface as aborts instead of silent stalls
When it happens
Trigger: Nonexistent hostname (dns error), server not listening / wrong port (connection refused), invalid or self-signed TLS certificate, network unreachable, proxy misconfiguration (bad HTTPS_PROXY/http_proxy env), or connecting through to a port blocked by policy.
Common situations: CI runners without network access; corporate proxies that intercept TLS; localhost vs 127.0.0.1 mismatch when only IPv6 resolves; dev servers not started; expired DNS; self-signed certs in staging environments.
Related errors
- BenchContext::start() has already been invoked
- The url passed into 'proxy.url' has an invalid scheme for th
- Unsupported transport: '${transport}'
- ERR_INVALID_ARG_TYPE
- ERR_INVALID_ARG_VALUE
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/01b00d8d8b5a1b1f.
Report an issue: GitHub.