Node.js betiğiniz haftalardır on dakikada bir aynı API'yi çağırıyor. Betiği bir CI sunucusuna taşıyorsunuz ya da bir iş arkadaşınız ofis ağında çalıştırıyor; artık her çağrı tek bir satırla bitiyor: TypeError: fetch failed. Ne sunucu adı var ne durum kodu. Adres tarayıcıda açılıyor, aynı makineden curl da API'ye ulaşıyor; mesaj sanki hiçbir şey söylemiyor.
Aslında söylüyor, yalnız mesajın içinde değil. Bu yazıda Node.js'in asıl nedeni nerede tuttuğunu, Node.js 22, 24 ve 26'da yeniden ürettiğimiz nedenleri, fetch'in proxy değişkenlerini neden görmediğini, Node.js 26'da proxy agent'larını bozan undici uyuşmazlığını ve nedeni tek satırda söyleyen, test edilmiş bir betiği anlatıyoruz.
"TypeError: fetch failed" ne anlama gelir?
Node.js'te 18. sürümden beri bulunan global fetch(), her Node.js sürümünün içinde gelen undici adlı HTTP istemcisinin üzerine kuruludur. Fetch standardı, ağ hatasıyla biten bir isteğin TypeError ile reddedilmesini ister. Bu hataların hepsinde undici aynı mesajı, fetch failed metnini kullanır ve asıl hatayı cause özelliğine ekler.
Ağ hatası, yanıttan önce ters giden her şeyi kapsar: ad çözümleme, TCP bağlantısı, TLS el sıkışması, proxy tüneli ya da başlıklar gelmeden kapanan bir bağlantı. 404 ya da 500 ağ hatası sayılmaz; fetch normal biçimde sonuçlanır ve res.ok değeri false olur.
Hatayı yakalayan bir kod yoksa Node.js nedeni kendisi yazdırır. Aşağıda, Node.js 26.10.0'da adı yanlış yazılmış bir sunucuya istek atan tek satırlık bir betiğin gerçek çıktısını görüyorsunuz:
[TypeError: fetch failed] {
[cause]: Error: getaddrinfo ENOTFOUND api.example-typo.invalid
at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:dns:122:26) {
errno: -3008,
code: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'api.example-typo.invalid'
}
}Sorun, kod hatayı yakalayıp yalnız mesajı yazdırdığında başlar; pek çok çatı (framework) ve SDK da bunu yapar. Nedeni görmek için bir satır daha yeter:
try {
await fetch("https://api.example-typo.invalid/v1/items");
} catch (err) {
console.log(err.message); // fetch failed
console.log(err.cause?.code, err.cause?.message); // ENOTFOUND getaddrinfo ENOTFOUND api.example-typo.invalid
}fetch failed hatasının arkasındaki asıl hata nasıl bulunur?
err.messagedeğil,err.causeyazdırın. Kullandığınız çatı hatayı yutuyorsa çağrıyı kendiniztry/catchiçine alın.cause.codedeğerini okuyun.Eile başlayan kodlar (ENOTFOUND,ECONNRESET) işletim sisteminden,UND_ERR_ile başlayanlar undici'den,UNABLE_TO_GET_ISSUER_CERT_LOCALLYgibi kodlar TLS katmanından gelir.AggregateErrorolup olmadığına bakın. Node.jslocalhostiçin birden fazla adres dener. Testimizdecause.messageboştu;cause.errorsiçinde biri::1, biri127.0.0.1için ikiECONNREFUSEDvardı.- Proxy hatalarında bir kat daha inin. Proxy girişi reddedildiğinde
causealanında kodsuz birRequest was cancelled.vardı; durum koduerr.cause.causeiçindeydi:Proxy response (407) !== 200 when HTTP Tunneling. - Hatanın ne kadar sürede geldiğine bakın. Birkaç milisaniye ret, sıfırlama ya da DNS cevabı demektir; 10 saniye civarı bağlantı zaman aşımıdır; beş dakika, başlıklar için varsayılan bekleme süresidir.
err.cause kodları: hangisi ne anlama gelir, ne düzeltilir?
Tablodaki her satırı Windows 11'de Node.js 24.21.0 ve 26.10.0 ile, yerel bir test proxy'si ve bağlantıyı reddeden, sıfırlayan, bekleten ya da test sertifikası sunan yerel sunucularla ürettik; iki sürüm de aynı kodları verdi. undici'nin hata başvuru sayfası UND_ERR_ kodlarını açıklar ve kullanılan dispatcher başka bir undici kopyasından gelebileceği için instanceof yerine error.code ile eşleştirmeyi önerir.
cause.code ve mesaj | Ne oldu | Önce neye bakılır |
|---|---|---|
ENOTFOUND getaddrinfo ENOTFOUND host | Alan adı çözülemiyor | Yazım, DNS, VPN |
ECONNREFUSED connect ECONNREFUSED 127.0.0.1:8999 | O portta dinleyen yok | Servis, port, proxy portu |
AggregateError içinde ECONNREFUSED | Aynısı, localhost'un her adresi için | Sunucuyu başlatın |
UND_ERR_CONNECT_TIMEOUT Connect Timeout Error | 10 sn içinde TCP bağlantısı yok | Adres, güvenlik duvarı |
ECONNRESET read ECONNRESET | TCP sıfırlamasıyla kesildi | Proxy, güvenlik duvarı; yeniden deneyin |
UND_ERR_SOCKET other side closed | Yanıttan önce kapandı | Sunucu kayıtları; yeniden deneyin |
UND_ERR_HEADERS_TIMEOUT Headers Timeout Error | Bağlandı, başlıklar zamanında gelmedi | Kendi süre sınırınız |
UNABLE_TO_GET_ISSUER_CERT_LOCALLY, SELF_SIGNED_CERT_IN_CHAIN | Kök sertifikaya güvenilmiyor | Şirketin kök sertifikası |
UNABLE_TO_VERIFY_LEAF_SIGNATURE | Sunucu ara sertifikayı göndermedi | Sunucunun sertifika zinciri |
ERR_SSL_WRONG_VERSION_NUMBER | Düz HTTP portuna TLS gönderildi | Proxy URL'sindeki https:// |
UND_ERR_INVALID_ARG invalid onError method | Başka bir undici sürümünün agent'ı | undici'nin kendi fetch'i |
| Kod yok: Request was cancelled. | Proxy tüneli reddetti | Proxy kimlik bilgileri |
Benzer ama fetch failed olmayan bir mesaj daha var: başlıklar gelir de gövde takılırsa res.text() ya da res.json() TypeError: terminated fırlatır; testimizde nedeni UND_ERR_BODY_TIMEOUT idi.
ENOTFOUND ve ECONNREFUSED: istek hiçbir sunucuya ulaşmadı
ENOTFOUND ad çözümleme adımından gelir: DNS çözümleyici böyle bir ad olmadığını söylemiştir. Yazım hatasına, kendi DNS sunucularını kullanan bir VPN'e ya da şirketin iç DNS'ine ulaşamayan bir konteynere bakın. Proxy arkasında adı proxy çözer, bu yüzden hatalı bir alan adı proxy'nin durum kodu olarak geri döner: test proxy'miz 502 verdi, fetch de bunu Proxy response (502) !== 200 when HTTP Tunneling diye bildirdi.
ECONNREFUSED, makinenin cevap verdiğini ama o portta bağlantı kabul eden bir program olmadığını gösterir. Mesajdaki adres proxy'nizin adresiyse sorun hedefte değil, proxy ayarındadır. Node.js localhost için hem ::1 hem 127.0.0.1 adresini dener; testimizde yalnız 127.0.0.1'e bağlı bir sunucu http://localhost adresine yine cevap verdi. İkisi de cevap vermiyorsa geliştirme sunucusu kapalıdır, başka bir portu kullanıyordur ya da kodunuz Docker içinde çalışıyordur; orada localhost konteynerin kendisidir.
ECONNRESET, "other side closed" ve "socket hang up"
Üçü de açılan bir bağlantının sonradan koptuğunu anlatır. Testte fetch'i http modülü ve Axios 1.20 ile karşılaştırdık:
- İsteğe TCP sıfırlamasıyla (RST) cevap veren bir sunucu, üç istemcide de
read ECONNRESETüretti. - Bağlantıyı yanıt göndermeden kapatan bir sunucu fetch'te
UND_ERR_SOCKET(other side closed),httpve Axios'ta iseECONNRESETkodlusocket hang upüretti.
Sık görülen nedenler şunlardır: sunucunun istek sırasında çökmesi, bir yük dengeleyicinin ya da proxy'nin boştaki keep-alive bağlantısını tam istemciniz onu yeniden kullanırken kapatması ya da bir güvenlik duvarının uzun süren bağlantıyı düşürmesi. Bazı sunucular ve bot filtreleri de hizmet vermek istemedikleri bağlantıları kapatır; bu, daha sık denemenin değil, yavaşlamanın ya da erişim istemenin işaretidir.
Tekrarlandığında sonucu değiştirmeyen (idempotent) GET ve HEAD isteklerini artan aralıklarla bir iki kez yeniden deneyin. Sipariş oluşturan bir POST'u körü körüne tekrarlamayın: bağlantı kopmadan önce sunucu işi bitirmiş olabilir.
Zaman aşımları: UND_ERR_CONNECT_TIMEOUT, UND_ERR_HEADERS_TIMEOUT ve AbortSignal.timeout()
Node.js'te fetch'in toplam bir süre sınırı yoktur. TCP bağlantısı için undici 10 saniye bekler; bağlantı kurulduktan sonra başlıklar için 300 saniyeye, gövde parçaları arasında da 300 saniyeye kadar bekler. Bağlantıyı kabul edip takılan bir sunucu isteği beş dakika tutabilir. Kendi sınırınızı koyun:
try {
const res = await fetch("https://api.example.com/v1/items", { signal: AbortSignal.timeout(5_000) });
console.log(res.status);
} catch (err) {
if (err.name === "TimeoutError") console.log("gave up after 5 s"); // 5 saniye doldu
else console.log(err.message, err.cause?.code);
}Hiç cevap vermeyen yerel bir sunucuya karşı bu kod Node.js 24 ve 26'da gave up after 5 s yazdırdı. MDN'nin AbortSignal.timeout() sayfasının belirttiği gibi sinyal TimeoutError ile iptal olur; hata fetch failed değildir, err.name ile kontrol edilir. Sınır gövdeyi de kapsar: takılan bir gövdede res.text() aynı TimeoutError hatasını verdi. Bu süreleri undici düzeyinde değiştirmek için npm paketinden bir Agent gerekir; bu da aşağıdaki sürüm sorusunu gündeme getirir.
fetch neden HTTP_PROXY ve HTTPS_PROXY değişkenlerini görmez?
curl, pip ve pek çok araç proxy ortam değişkenlerini kendiliğinden okur; Node.js'in fetch'i okumaz. HTTPS_PROXY tanımlıyken Node.js 22.23.3, 24.21.0 ve 26.10.0'da fetch doğrudan hedefe gitti ve proxy kaydımız boş kaldı; curl ise proxy'yi kullandı. İnternete yalnız proxy'nin çıkabildiği bir ağda cause hedefi gösterir (ENOTFOUND, UND_ERR_CONNECT_TIMEOUT), atlanan proxy'den hiç söz etmez.
Node.js'in yerleşik proxy desteği bunu açar: NODE_USE_ENV_PROXY=1 (Node.js 22.21.0 ve 24.0.0'dan itibaren) ya da --use-env-proxy seçeneği (22.21.0 ve 24.5.0'dan itibaren). Node.js bu durumda HTTP_PROXY, HTTPS_PROXY ve NO_PROXY değişkenlerini açılışta okur ve hem fetch'te hem http ile https modüllerinde kullanır. Belgeler özelliği hâlâ "aktif geliştirme" aşamasında gösteriyor.
NODE_USE_ENV_PROXY=1 HTTPS_PROXY="http://user:pass@pr.proxynet.io:8000" NO_PROXY="localhost,127.0.0.1" node app.mjsPowerShell'de:
$env:NODE_USE_ENV_PROXY = "1"
$env:HTTPS_PROXY = "http://user:pass@pr.proxynet.io:8000"
node app.mjsBundan sonra test proxy'miz üç sürümde de CONNECT example.com:443 kaydetti; Node.js 22 ayrıca EnvHttpProxyAgent özelliğinin deneysel olduğu uyarısını bastı. Üç ayrıntı sık atlanır:
- Proxy URL'si
https://hedeflerde dehttp://ile başlar. Tünel isteği düz HTTP'dir, TLS tünelin içinde çalışır; düz HTTP proxy'sinin önünehttps://yazıncaERR_SSL_WRONG_VERSION_NUMBERaldık. - Aynı işi koddan
http.setGlobalProxyFromEnv()yapar. Node.js 24.14.0 ve 25.4.0'dan beri vardır; Node.js 22'de yoktur. - Yanlış şifre bir kat aşağıda saklanır,
err.cause.causeiçinde.
Residential Proxy hizmetimiz gibi bir sağlayıcının bağlantı adresi de aynı değişkene http://user:pass@pr.proxynet.io:8000 biçiminde yazılır; sunucunuzun IP'si IP whitelist'teyse kimlik bilgisine de gerek kalmaz.
İstek başına proxy, Axios ve SOCKS5 için Node.js'te proxy kullanımı rehberimizi izleyin.
Node.js 26 ve "invalid onError method": undici sürüm uyuşmazlığı
Her Node.js sürümü npm'deki undici paketinden ayrı, kendi undici kopyasını taşır: Node.js 22.23.3'te undici 6.28.1, 24.21.0'da 7.29.1, 26.10.0'da 8.10.2 var. 8.0.0 sürümünde undici, eski işleyici (handler) kodunun yeni kodla konuşmasını sağlayan sarmalayıcıları kaldırdı. Node.js sürüm takvimine göre Node.js 26, 28 Ekim 2026'da Active LTS hattı oluyor; pek çok proje bu hatayla yükseltme sırasında karşılaşacak.
Hata, npm paketinden oluşturulan bir ProxyAgent ya da Agent global fetch'e dispatcher olarak verildiğinde çıkar. Dört npm ana sürümünü üç Node.js sürümünde denedik:
| npm undici | Node.js 22.23.3 | Node.js 24.21.0 | Node.js 26.10.0 |
|---|---|---|---|
| 5.29.0 | çalışıyor | çalışıyor | invalid onError method |
| 6.29.0 | çalışıyor | çalışıyor | invalid onError method |
| 7.30.0 | çalışıyor | çalışıyor | çalışıyor |
| 8.11.2 | invalid onRequestStart method | invalid onRequestStart method | çalışıyor |
Her hata, nedeni UND_ERR_INVALID_ARG olan bir TypeError: fetch failed idi. Daha sessiz bir türü ise daha da kötü: Node.js 26'da undici 5 ya da 6'dan gelen setGlobalDispatcher(new ProxyAgent(...)) hiç hata vermedi, fetch onu yok saydı ve istek doğrudan çıktı; proxy'miz hiçbir şey görmedi.
Çözüm, fetch'i agent ile aynı paketten almaktır:
import { fetch, ProxyAgent } from "undici"; // fetch ve agent aynı paketten
const proxy = new ProxyAgent("http://user:pass@pr.proxynet.io:8000");
const res = await fetch("https://example.com/", { dispatcher: proxy });
console.log(res.status); // testimizde yerel bir test proxy'si üzerinden 200Bu kod undici 8.11.2 ile Node.js 24 ve 26'da çalıştı. Uyuşmazlık sizin yazmadığınız bir araçtaysa, örneğin eski bir undici taşıyıp proxy değişkenlerinizden agent kuran bir CLI'daysa, aracı güncelleyin ya da düzeltme gelene kadar Node.js 24'te çalıştırın.
fetch failed hatasının arkasındaki sertifika hataları
Başarısız bir TLS doğrulaması da fetch failed olarak gelir; sertifika kodu cause.code içindedir. İş yerinde en sık kaynak, HTTPS trafiğini inceleyip kendi kök sertifikasıyla yeniden imzalayan bir şirket proxy'si ya da antivirüstür. Node.js sertifikaları işletim sisteminin listesine değil, kendi içinde gelen kök sertifika listesine göre doğrular; bu yüzden o kökü UNABLE_TO_GET_ISSUER_CERT_LOCALLY ya da SELF_SIGNED_CERT_IN_CHAIN ile reddeder.
NODE_EXTRA_CA_CERTS değişkenini şirketin kök sertifikasını içeren bir PEM dosyasına yönlendirin; kök makinede zaten kuruluysa Node.js'i --use-system-ca ile çalıştırın (22.15.0 ve 23.8.0'dan beri). Testimizde NODE_EXTRA_CA_CERTS ilk durumu çözdü ama UNABLE_TO_VERIFY_LEAF_SIGNATURE hatasını çözmedi: orada sunucu ara sertifikasını göndermiyor ve bunu yalnız sunucunun sahibi düzeltebilir. npm, Git, Python ve curl için çözümler Unable to Get Local Issuer Certificate yazımızda.
Nedeni söyleyen ve yeniden deneyen bir fetch sarmalayıcısı
Betik global fetch'i kullanır, bu yüzden paket kurmanız gerekmez. Hata zincirinin tamamını gezer, her denemeyi AbortSignal.timeout() ile sınırlar ve yalnız sıfırlanan ya da kapanan bağlantılarla zaman aşımlarını, üstel bekleme (backoff) ve jitter ile yeniden dener. DNS hataları, retler, sertifika hataları ve reddedilen proxy girişi her seferinde aynı biçimde düştüğü için bunlarda durur. 429 ve 503 yanıtlarında Retry-After süresi kadar bekler.
429, sunucunun sizden yavaşlamanızı istemesidir. Retry-After başlığının ne anlama geldiğini ve bir işin hızının nasıl ayarlanacağını 429 Too Many Requests ve Rate Limit Hatası Nedir? yazımızda anlattık.
// fetch-check.mjs: "TypeError: fetch failed" hatasının asıl nedenini söyler, yalnız düzelebilecek olanı yeniden dener.
// Node.js 22, 24 ve 26'da test edildi. İsteğe bağlı proxy: NODE_USE_ENV_PROXY=1 HTTPS_PROXY=http://user:pass@pr.proxynet.io:8000
const RETRY_CODES = new Set(["ECONNRESET", "UND_ERR_SOCKET", "UND_ERR_CONNECT_TIMEOUT"]);
const CERT_CODES = /CERT|SELF_SIGNED|UNABLE_TO_(GET|VERIFY)/;
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
/** Hatanın kendisi ve içine sarılmış her hata, dıştan içe. */
function causes(err) {
const chain = [];
for (let e = err; e && chain.length < 8; e = e.cause) {
chain.push(e);
if (e instanceof AggregateError) chain.push(...e.errors); // "localhost": her adres için bir hata
}
return chain;
}
/** Zincirdeki ilk metin hata kodu, ör. "ECONNRESET". */
const codeOf = (err) => causes(err).map((e) => e.code).find((c) => typeof c === "string") ?? "";
/** Tek satır: ne düştü ve önce neye bakılmalı. */
function explain(err) {
if (err.name === "TimeoutError") return "no answer before our AbortSignal.timeout(): slow server or proxy";
const chain = causes(err);
const text = chain.map((e) => e.message).join(" | ");
const code = codeOf(err);
const tunnel = text.match(/Proxy response \((\d{3})\)/);
if (tunnel?.[1] === "407") return "proxy wants credentials (407): check user:pass or the IP whitelist";
if (tunnel) return `proxy refused the tunnel (${tunnel[1]}): the proxy could not or would not reach the target`;
if (code === "ENOTFOUND") return `name ${chain.find((e) => e.hostname)?.hostname} does not resolve: typo, DNS or VPN`;
if (code === "ECONNREFUSED") return "nothing listens on that address and port: wrong port, service down or wrong proxy port";
if (code === "ECONNRESET") return "the connection was cut (TCP reset): server, proxy or firewall dropped it";
if (code === "UND_ERR_SOCKET") return "the other side closed the connection before answering";
if (code === "UND_ERR_CONNECT_TIMEOUT") return "no TCP connection within 10 s: wrong IP, firewall or blocked outbound port";
if (code === "UND_ERR_HEADERS_TIMEOUT") return "connected, but no response headers in time";
if (code === "ERR_SSL_WRONG_VERSION_NUMBER") return "TLS spoken to a plain-HTTP port: the proxy URL should start with http://";
if (CERT_CODES.test(code)) return `certificate not trusted (${code}): add your CA with NODE_EXTRA_CA_CERTS`;
return `unrecognised, read the innermost error: ${chain.at(-1).message}`;
}
/** Kesin süre sınırı, ağ kesintilerinde bekleme ve 429/503'te Retry-After ile GET. */
async function getWithRetry(url, { attempts = 3, timeoutMs = 15_000 } = {}) {
for (let attempt = 1; ; attempt++) {
const backoff = 500 * 2 ** (attempt - 1) + Math.random() * 250; // 0,5 sn, 1 sn, 2 sn ... artı jitter
let res;
try {
res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });
} catch (err) {
const code = codeOf(err);
const retryable = RETRY_CODES.has(code) || err.name === "TimeoutError";
if (!retryable || attempt === attempts) throw err;
console.log(` attempt ${attempt}: ${code || err.name}, retrying in ${Math.round(backoff)} ms`);
await sleep(backoff);
continue;
}
if ((res.status === 429 || res.status === 503) && attempt < attempts) {
const wait = Number(res.headers.get("retry-after")) * 1000 || backoff; // yalnız saniye biçimi
await res.body?.cancel();
console.log(` attempt ${attempt}: HTTP ${res.status}, waiting ${Math.round(wait)} ms`);
await sleep(wait);
continue;
}
return res;
}
}
for (const url of process.argv.slice(2)) {
console.log(url);
try {
const res = await getWithRetry(url, { timeoutMs: 5_000 });
console.log(` OK: HTTP ${res.status}`);
} catch (err) {
console.log(` FAILED: ${err.name}: ${err.message} -> ${explain(err)}`);
}
}Çıktı nasıl görünüyor?
Betiği Node.js 26.10.0'da yanlış yazılmış bir alan adına, localhost üzerinde kapalı bir porta ve her bağlantıyı sıfırlayan (8902), hiç cevap vermeyen (8901), kendi test sertifika otoritemizin sertifikasını kullanan (8906) ve başarıdan önce iki kez 429 dönen (8910) yerel sunuculara karşı çalıştırdık:
https://api.example-typo.invalid/
FAILED: TypeError: fetch failed -> name api.example-typo.invalid does not resolve: typo, DNS or VPN
http://localhost:8999/
FAILED: TypeError: fetch failed -> nothing listens on that address and port: wrong port, service down or wrong proxy port
http://127.0.0.1:8902/
attempt 1: ECONNRESET, retrying in 652 ms
attempt 2: ECONNRESET, retrying in 1115 ms
FAILED: TypeError: fetch failed -> the connection was cut (TCP reset): server, proxy or firewall dropped it
http://127.0.0.1:8901/
attempt 1: TimeoutError, retrying in 658 ms
attempt 2: TimeoutError, retrying in 1024 ms
FAILED: TimeoutError: The operation was aborted due to timeout -> no answer before our AbortSignal.timeout(): slow server or proxy
https://127.0.0.1:8906/
FAILED: TypeError: fetch failed -> certificate not trusted (UNABLE_TO_GET_ISSUER_CERT_LOCALLY): add your CA with NODE_EXTRA_CA_CERTS
http://127.0.0.1:8910/items
attempt 1: HTTP 429, waiting 1000 ms
attempt 2: HTTP 429, waiting 1000 ms
OK: HTTP 200Ardından NODE_USE_ENV_PROXY=1 ile yerel test proxy'si üzerinden üç deneme: doğru şifre, yanlış şifre ve proxy adresinin önünde https://:
https://example.com/
OK: HTTP 200
https://example.com/
FAILED: TypeError: fetch failed -> proxy wants credentials (407): check user:pass or the IP whitelist
https://example.com/
FAILED: TypeError: fetch failed -> TLS spoken to a plain-HTTP port: the proxy URL should start with http://Node.js 22.23.3 ve 24.21.0, rastgele bekleme süreleri dışında aynı satırları yazdırdı.
Bu hatayla nerede karşılaşırsınız?
- Next.js ve sunucu tarafında çalışan diğer çatılarda: hata sayfaları çoğu zaman yalnız mesajı gösterir.
- MCP sunucularında ve yapay zekâ ajanı araçlarında: bunlar çoğu zaman bir VPN ya da şirket proxy'si arkasında çalışır.
- fetch üzerine kurulu SDK'larda: bazı istemcilerin eski sürümleri nedeni hiç aktarmıyordu.
- CI sunucularında ve Docker derlemelerinde: konteynerlerde çoğu zaman makinenin proxy değişkenleri ve şirketin kök sertifikası yoktur.
- Scraping ve izleme işlerinde: uzun süren çalışmalar tablodaki kodların çoğuyla er geç karşılaşır.
Yukarıdaki sarmalayıcıdan en çok uzun süren veri toplama işleri yararlanır. Böyle bir iş az sayıda bilinen hedefle çalışıyor ve haftalarca değişmeyen çıkış IP'lerine ihtiyaç duyuyorsa Datacenter Proxy, size ayrılmış IPv4 adreslerini trafik sınırı olmadan verir.
Sık yapılan hatalar
err.messageyazdırmak. Her zamanfetch failedder.- fetch'in
HTTPS_PROXYokumasını beklemek.NODE_USE_ENV_PROXY=1ya da--use-env-proxyolmadan okumaz. - npm'deki undici agent'ını global fetch'e vermek.
fetch'i aynı paketten alın. - Sertifika doğrulamasını kapatmak.
NODE_TLS_REJECT_UNAUTHORIZED=0doğrulamayı bütün süreç için kapatır; araya giren bir saldırgan da şirket proxy'niz gibi görünür. - Her şeyi yeniden denemek. Yazım hatası her seferinde aynı biçimde düşer;
ECONNRESETsonrası tekrarlanan bir POST iki kez çalışabilir. - Süre sınırı koymamak. Takılan bir sunucu isteği beş dakika tutabilir.
Karar rehberi
err.cause içinde gördüğünüz | Ne yapmalı |
|---|---|
ENOTFOUND | Alan adını ya da DNS'i düzeltin; yeniden denemeyin |
Proxy adresinizle ECONNREFUSED | Proxy adresini ve portunu yeniden kopyalayın |
localhost üzerinde ECONNREFUSED | Sunucuyu başlatın; portu ve Docker'ı kontrol edin |
ECONNRESET, UND_ERR_SOCKET | GET isteklerini artan aralıklarla yeniden deneyin |
UND_ERR_CONNECT_TIMEOUT | Güvenlik duvarına bakın; şirket proxy'si arkasında NODE_USE_ENV_PROXY=1 |
Uzun bekleme, sonra UND_ERR_HEADERS_TIMEOUT | AbortSignal.timeout() ekleyin |
| Bir sertifika kodu | NODE_EXTRA_CA_CERTS ya da --use-system-ca |
Bir kat aşağıda Proxy response (407) | user:pass bilgisini ya da IP whitelist'i kontrol edin |
invalid onError method | fetch'i agent ile aynı undici paketinden alın |
Sıkça sorulan sorular
fetch 404 ya da 500'de neden hata fırlatmıyor?
Çünkü sunucu cevap vermiştir. Ortada bir ağ hatası olmadığı için fetch normal biçimde sonuçlanır; HTTP hata kodunda res.ok değeri false olur. Gövdeyi okumadan önce bunu kontrol edin.
"fetch failed" ile tarayıcıdaki "Failed to fetch" aynı şey mi?
Akraba ama aynı değil. Chrome hatayı TypeError: Failed to fetch ile reddeder ve nedenini sayfaya söylemez; bu yüzden CORS engeli de koddan aynı görünür, nedeni DevTools'taki Network (Ağ) sekmesinde görürsünüz. Node.js ise nedeni cause içine koyar.
Node.js'te fetch için zaman aşımı nasıl ayarlanır?
signal: AbortSignal.timeout(ms) verin. Süre dolunca fetch TimeoutError ile reddedilir ve sınır takılan bir gövdeyi de durdurur.
Node.js fetch HTTP_PROXY ve HTTPS_PROXY değişkenlerini kullanır mı?
Yalnız NODE_USE_ENV_PROXY=1 (22.21.0, 24.0.0 ve sonrası) ya da --use-env-proxy (22.21.0, 24.5.0 ve sonrası) ile. Bunlar olmadan değişkenler hiçbir uyarı vermeden yok sayılır.
Aynı makinede curl çalışırken fetch neden hata veriyor?
Genellikle iki nedenden biri: curl proxy değişkenlerini okur, fetch okumaz; Windows'la gelen sürüm de dahil pek çok curl derlemesi sertifikaları işletim sisteminin deposuna göre doğrular, Node.js ise --use-system-ca verilmedikçe kendi listesini kullanır.
Proxy "TypeError: fetch failed" hatasını çözer mi?
Yalnız sorun ağ yolundaysa, örneğin internete yalnız proxy'nin çıkabildiği bir şirket ağında. Yazım hatasını, sertifika sorununu ya da kapalı bir sunucuyu düzeltmez. Bağlantınızı sıfırlayan ya da size hız sınırı (rate limit) uygulayan bir siteyi dolanmanın yolu da değildir: yavaşlayın, sitenin resmî API'sini kullanın ya da erişim isteyin.
Özet
TypeError: fetch failed bir sarmalayıcıdır: asıl neden err.cause içindedir, bazen bir kat daha aşağıda. Kodu okuyun, söylediği şeyi düzeltin, her çağrıya bir AbortSignal.timeout() verin ve yalnız sıfırlamaları ve zaman aşımlarını yeniden deneyin. Proxy arkasında NODE_USE_ENV_PROXY=1 kullanın, proxy URL'sini http:// ile yazın ve özellikle Node.js 26'ya geçerken fetch ile agent'ı aynı undici paketinden alın. Kodunuz proxy ile çalışmaya hazır olduğunda seçenekleri proxy hizmetlerimiz sayfasında karşılaştırabilirsiniz.




