Web API'leri bir hata durumunu çoğunlukla DOMException nesnesiyle bildirir. Her DOMException'ın hatayı tanımlayan, PascalCase biçiminde bir name değeri (NotAllowedError, AbortError, SecurityError, QuotaExceededError, TimeoutError...), açıklayıcı bir message metni ve eskiden kalma sayısal bir code değeri vardır. Kodunuzda hatayı ayırt etmek için her zaman name özelliğini kullanın. Hataların önemli bir kısmı ise üç ortak kaynaktan gelir: API'nin güvenli bağlam (HTTPS) istemesi, kullanıcı izni gerektirmesi ya da yalnızca kullanıcı etkinliğinden (bir tıklama gibi) hemen sonra çalışması.
Bu yazı serinin hata başvuru sayfasıdır: hata adlarının anlamları, hangi API'nin hangi adı fırlattığına dair örnekler, güvenli bağlamın tam tanımı, geçici ve kalıcı kullanıcı etkinliği farkı ve fetch() çağrısında görülen "Failed to fetch" türü hataların nasıl okunacağı. DOMException ve AbortSignal örnekleri tarayıcıda da aynı çalışan standart API'ler oldukları için Node.js ile çalıştırıldı. Serinin haritası için Web API öğrenme rehberi, CORS hataları için CORS hataları ve çözümleri yazısına bakın.
DOMException nedir?
MDN'e göre DOMException, bir Web API'sinin metodunu çağırırken ya da bir özelliğine erişirken ortaya çıkan olağan dışı durumu (istisnayı) temsil eden arayüzdür; Web API'lerinde hata koşulları bu yolla anlatılır. Nesnenin üç örnek özelliği vardır. name hatanın adıdır. message bu adla ilişkili açıklamadır ve içeriği tarayıcıdan tarayıcıya değişebileceği için koşullarda kullanılmamalıdır. code ise eski hata sabitlerinden birini ya da eşleşme yoksa 0 döndürür; MDN, yeni hataların artık bu alanı kullanmadığını ve bilgiyi name içine koyduğunu belirtir.
DOMException serileştirilebilir bir nesnedir; structuredClone() ile kopyalanabilir ve postMessage() ile worker'lara aktarılabilir. Yapıcısı new DOMException(message, name) biçimindedir: message verilmezse boş dize, name verilmezse 'Error' kullanılır. Ad standart bir hata adıysa code özelliği ona karşılık gelen eski numarayı döndürür. Aşağıdaki örnek bunları ve iki gerçek hata kaynağını gösterir: serileştirilemeyen bir fonksiyonu kopyalamaya çalışan structuredClone() DataCloneError, geçersiz base64 alan atob() InvalidCharacterError fırlatır.
const e1 = new DOMException('Kamera izni reddedildi', 'NotAllowedError');
console.log(e1.name, e1.message, e1.code); // NotAllowedError Kamera izni reddedildi 0
const e2 = new DOMException('İşlem iptal edildi', 'AbortError');
console.log(e2.name, e2.code); // AbortError 20
const e3 = new DOMException();
console.log(JSON.stringify(e3.name), JSON.stringify(e3.message), e3.code); // "Error" "" 0
const kopya = structuredClone(e1);
console.log(kopya.name, kopya.message, kopya instanceof DOMException);
// NotAllowedError Kamera izni reddedildi true
try {
structuredClone({ f: () => 1 });
} catch (hata) {
console.log(hata instanceof DOMException, hata.name, hata.code); // true DataCloneError 25
}
try {
atob('***');
} catch (hata) {
console.log(hata.name, hata.code); // InvalidCharacterError 5
}NotAllowedError için code değerinin 0 olmasının nedeni, bu adın eski bir sayısal sabite sahip olmamasıdır. structuredClone() ayrıntıları için Web Workers ve postMessage yazısına bakabilirsiniz.
Hata adları ve anlamları

MDN yaygın hata adlarını listeler ve bazı API'lerin kendi adlarını tanımladığını, listenin bu yüzden tam olmadığını not eder. Aşağıdaki tablo uygulamada en sık karşılaşılanları ve MDN'de geçtikleri tipik yerleri özetler.
| Ad | Eski kod | Anlamı | Tipik kaynak |
|---|---|---|---|
| NotAllowedError | yok | Kullanıcı aracısı ya da platform isteğe bu bağlamda izin vermiyor, kullanıcı izni reddetmiş olabilir | getUserMedia, Clipboard, WebAuthn, izin politikası |
| AbortError | 20 | İşlem iptal edildi | AbortController ile iptal edilen fetch, WebAuthn |
| TimeoutError | 23 | İşlem zaman aşımına uğradı | AbortSignal.timeout() |
| SecurityError | 18 | İşlem güvensiz | Geçersiz alan adı (credentials.get), devre dışı medya desteği |
| QuotaExceededError | 22 | Kota aşıldı | localStorage.setItem, depolama API'leri |
| NotFoundError | 8 | Nesne bulunamadı | İstenen türde medya izi yok |
| NotReadableError | yok | Giriş/çıkış okuma işlemi başarısız | Kamera izin verildiği halde donanım hatası |
| NotSupportedError | 9 | İşlem desteklenmiyor | Desteklenmeyen seçenek veya tür |
| InvalidStateError | 11 | Nesne geçersiz durumda | Tam etkin olmayan belgede Permissions.query, getUserMedia |
| DataCloneError | 25 | Nesne kopyalanamıyor | structuredClone, postMessage |
| InvalidCharacterError | 5 | Dize geçersiz karakter içeriyor | atob() |
| HierarchyRequestError | 3 | Düğüm ağacı hiyerarşisi yanlış | DOM ekleme metotları |
| SyntaxError | 12 | Dize beklenen kalıba uymuyor | Geçersiz CSS seçici ile querySelector |
| ConstraintError, VersionError, TransactionInactiveError, ReadOnlyError | yok | IndexedDB işlem ve sürüm hataları | IndexedDB |
| NetworkError | 19 | Ağ hatası oluştu | Bazı API'ler (ör. FedCM kimlik isteği) |
Tablodaki "eski kod" sütunu yalnızca geriye dönük uyumluluk içindir; yeni kod yazarken bu sayılara değil adlara bakın. QuotaExceededError için MDN ayrıca bunun artık DOMException'dan türeyen ayrı bir arayüz olduğunu, bu arayüzü uygulayan tarayıcılarda quota ve requested özellikleriyle ek bilgi taşıyabildiğini, daha eski sürümlerde ise düz bir DOMException olduğunu belirtir; ayrıntı ve destek için MDN uyumluluk tablosuna bakın. TypeMismatchError ise kullanımdan kalkmıştır; yerine JavaScript'in TypeError hatası fırlatılır. Depolama kotası konusu Storage API ve depolama kotası, IndexedDB hataları IndexedDB kullanımı yazısında.
İptal ve zaman aşımı: AbortError ve TimeoutError
İki hata adı kendi kodunuzdan da gelir. AbortController.abort() nedeni (reason) verilmeden çağrıldığında sinyalin reason değeri AbortError adlı bir DOMException olur; bir neden verilirse bu değer olduğu gibi kullanılır. MDN'in credentials.get() sayfası da, abort() çağrısına bir neden geçilirse işlemin AbortError yerine o değerle reddedileceğini not eder. AbortSignal.timeout() ile oluşturulan sinyal ise süre dolduğunda TimeoutError adlı bir DOMException ile iptal olur.
const kontrol = new AbortController();
kontrol.abort();
console.log(kontrol.signal.aborted, kontrol.signal.reason.name); // true AbortError
const ozel = new AbortController();
ozel.abort(new Error('kullanıcı vazgeçti'));
console.log(ozel.signal.reason.name, ozel.signal.reason.message); // Error kullanıcı vazgeçti
const sure = AbortSignal.timeout(10);
await new Promise((coz) => setTimeout(coz, 50));
console.log(sure.aborted, sure.reason.name, sure.reason instanceof DOMException);
// true TimeoutError true
try {
kontrol.signal.throwIfAborted();
} catch (hata) {
console.log(hata.name); // AbortError
}Bu ayrım kullanıcı arayüzü için önemlidir: AbortError genellikle kullanıcının ya da kodunuzun bilinçli bir iptalidir ve hata mesajı göstermeyi gerektirmez, TimeoutError ise "tekrar deneyin" gibi bir yanıtı hak eder. MDN, AbortSignal.timeout() için zamanlayıcıyı iptal etmenin bir yolu olmadığını ve işlem erken bitse bile zaman aşımının sürdüğünü de belirtir. Fetch ile zaman aşımı kullanımı Fetch API kullanımı yazısında.
"Failed to fetch" ve fetch() hataları
fetch() iki farklı biçimde başarısız olur ve bunları karıştırmak en sık hatadır. MDN'e göre sunucu 404 gibi bir hata koduyla yanıt verdiğinde fetch() reddedilmez, bir Response ile yerine getirilir; bu yüzden response.ok ya da response.status değerini kendiniz kontrol etmeniz gerekir. Promise yalnızca ağ hatası ya da hatalı şema gibi durumlarda reddedilir. Bu durumda gelen hata çoğunlukla bir TypeError'dır; MDN'in fetch() sayfası geçersiz URL, kimlik bilgisi içeren URL, geçersiz seçenek değerleri, izin politikası engeli ve bağlantı yokluğu gibi ağ hatalarını TypeError nedenleri olarak sayar. AbortController ile iptal edilirse AbortError, izin politikasıyla engellenen bazı özelliklerde NotAllowedError gelir.
"Failed to fetch" bir hata adı değil, bu TypeError'ın mesaj metnidir. MDN'in Request.cache örneği, Chrome'un bu durumda mesajı "Failed to fetch" olan bir TypeError fırlattığını gösterir; diğer tarayıcılarda metin farklıdır. Bu yüzden koşulunuzu mesaja değil, hatanın türüne dayandırın. CORS reddi de koda yalnızca bir hata olarak ulaşır: MDN, güvenlik nedeniyle CORS isteğinde neyin yanlış gittiğinin JavaScript'e bildirilmediğini, ayrıntının yalnızca tarayıcı konsolunda görülebildiğini vurgular. Konsoldaki mesajların tek tek açıklaması CORS hataları yazısında, HTTP durum kodları HTTP durum kodları yazısında, Node.js tarafındaki fetch hataları ise Node.js fetch yazısında.
async function veriGetir(url) {
try {
const yanit = await fetch(url, { signal: AbortSignal.timeout(8000) });
if (!yanit.ok) {
throw new Error(`Sunucu hatası: ${yanit.status}`); // 404, 500 gibi yanıtlar buraya düşer
}
return await yanit.json();
} catch (hata) {
if (hata.name === 'TimeoutError') {
// süre doldu
} else if (hata.name === 'AbortError') {
// başka bir yerde iptal edildi
} else if (hata instanceof TypeError) {
// ağ hatası, CORS reddi veya geçersiz istek; ayrıntı konsolda
}
throw hata;
}
}Karma içerik de bu belirtiyle karşınıza çıkabilir: HTTPS bir sayfadan http:// adresine yapılan istekler engellenir. Çözüm için karma içerik hatası yazısına bakın.
Güvenli bağlam (secure context)

Güvenli bağlam, belirli kimlik doğrulama ve gizlilik standartlarını karşılayan bir Window ya da Worker ortamıdır. MDN, bazı API'lerin kullanıcının gizliliğini ihlal etme, bilgisayarına düşük seviyeli erişim ya da kimlik bilgileri gibi verilere ulaşma gücü verdiğini, bunlar güvenli olmayan bağlantıyla sunulan içerikte kullanılabilseydi araya giren bir saldırganın (MITM) da bunlara erişebileceğini açıklar. Bu yüzden Service Worker, Web Crypto, Web Authentication, Clipboard, Geolocation, Notifications, Push, Storage API, Cookie Store API ve daha birçok API yalnızca güvenli bağlamda kullanılabilir; getUserMedia() gibi bazı metotlar da API'nin geri kalanı öyle olmasa bile güvenli bağlam ister.
Kabaca, kaynakları HTTPS üzerinden ya da yerel geri döngü (loopback) adresinden gelen belgeler güvenli bağlamdır. Çerçevedeki belgeler için ek bir koşul vardır: kendileri güvenilir bir URL'den gelmeli ve güvenli bir bağlamın içine gömülmüş olmalıdır. Worker'lar onları oluşturan bağlam güvenliyse güvenlidir; service worker yalnızca güvenli bağlamlardan kaydedilebildiği için her zaman güvenlidir.
| Adres | Güvenli bağlam mı? |
|---|---|
| https://example.com | Evet (https) |
| http://localhost | Evet (localhost) |
| file:///yol/sayfa.html | Evet (file) |
| http://example.com | Hayır (http) |
| https iframe, http üst belge içinde | Hayır (üst bağlam güvenli değil) |
| http iframe, https üst belge içinde | Hayır (iframe adresi güvenli değil) |
MDN'e göre potansiyel olarak güvenilir kökenler şunlardır: şeması https, wss veya file olanlar; ana makinesi 127.0.0.0/8 ya da ::1/128 aralığında olanlar; ana makinesi localhost veya .localhost ile bitenler ve tarayıcının kimliği doğrulanmış saydığı şemalar (örneğin tarayıcı eklentilerinin kullandıkları). Bu yüzden geliştirme sırasında http://localhost üzerinde çalışan bir özellik, yerel ağdaki http://192.168.1.20 adresinden açıldığında güvenli bağlam olmadığı için çalışmayabilir. Kodda kontrol için window.isSecureContext veya worker içinde WorkerGlobalScope.isSecureContext kullanılır.
if (window.isSecureContext) {
// güvenli bağlam: service worker kaydı yapılabilir
navigator.serviceWorker.register('/offline-worker.js');
} else {
// HTTP üzerinden açılmış: güvenli bağlam gerektiren özellikleri gizle
}Güvenli olmayan bağlamda API'ler her zaman hata fırlatmaz; bazen hiç bulunmaz. MDN'in getUserMedia() sayfası, güvensiz bağlamda navigator.mediaDevices değerinin undefined olduğunu, bu yüzden çağrının TypeError ile sonuçlanabileceğini belirtir. Aynı sayfa, güvensiz bağlamda cihazlar kullanılamıyorsa NotAllowedError geldiğini de söyler. Yani "undefined" ya da "is not a function" türü bir hata gördüğünüzde ilk kontrol, sayfanın HTTPS ile açılıp açılmadığıdır. HTTPS kurulumu için HTTPS ve TLS rehberi yazısına bakın.
İzinler ve Permissions API
Kamera, mikrofon, konum ve bildirim gibi güçlü özellikler kullanıcının iznini ister. Kullanıcı izni reddettiğinde ya da tarayıcı bu bağlamda izin vermediğinde API'ler genellikle NotAllowedError fırlatır. İzin durumunu önceden öğrenmek için navigator.permissions.query() kullanılabilir; dönen PermissionStatus nesnesinin state değeri 'granted', 'denied' veya 'prompt' olur. MDN, 'prompt' durumunun pratikte reddedilmişle aynı olduğunu, özellik kullanılmaya çalışılınca kullanıcıya sorulacağını ya da erişimin reddedileceğini açıklar. Tarayıcının desteklemediği bir izin adı sorgulanırsa promise TypeError ile reddedilir; desteklenen adlar için MDN uyumluluk tablosuna bakın.
const durum = await navigator.permissions.query({ name: 'geolocation' });
if (durum.state === 'granted') {
konumluIcerigiGoster();
} else if (durum.state === 'prompt') {
izinIsteyenDugmeyiGoster();
}
durum.addEventListener('change', () => {
// kullanıcı izni tarayıcı ayarlarından değiştirdi
});İzinlerin bir diğer katmanı Permissions-Policy başlığı ve iframe'lerdeki allow özniteliğidir. Bir özellik politika tarafından engellenmişse kullanıcı ne seçerse seçsin çağrı NotAllowedError ile reddedilir; MDN bunu getUserMedia, WebAuthn ve credentials sayfalarında ayrı ayrı belirtir. Kamera ve bildirim izinlerinin ayrıntıları getUserMedia ve Notifications API yazılarında.
Kullanıcı etkinliği: geçici ve kalıcı

Bazı API'ler, kötüye kullanımı önlemek için yalnızca kullanıcı sayfayla etkileşim halindeyken ya da en az bir kez etkileşime girdiyse çalışır. MDN'e göre etkinliği tetikleyen girdi olayı, isTrusted değeri true olan ve şu türlerden biri olan olaydır: keydown (Esc, tarayıcıya ayrılmış kısayollar ve Caps Lock gibi bazı tuşlar hariç), mousedown, pointerType değeri fare olan pointerdown, fare olmayan pointerup ve touchend. Kodla tetiklenen click() gibi sahte olaylar isTrusted taşımadığı için etkinlik sağlamaz.
| Tür | Süresi | Gerektiren API örnekleri |
|---|---|---|
| Geçici (transient) etkinlik | Kısa bir zaman aşımıyla biter, bazı API'ler onu tüketir | Clipboard.writeText ve readText, Window.open, requestFullscreen, showOpenFilePicker, Navigator.share, getDisplayMedia |
| Kalıcı (sticky) etkinlik | Oturum sonuna kadar sürer | beforeunload olayı, Navigator.vibrate, medya otomatik oynatma |
Pratik sonuç şudur: geçici etkinlik gerektiren bir API'yi sayfa yüklenirken ya da uzun bir await zincirinin sonunda çağırırsanız etkinlik süresi dolmuş olabilir ve çağrı reddedilir. Bu çağrıları doğrudan bir tıklama işleyicisinin içinde, mümkünse ilk adımlarda yapın. Durumu kodla öğrenmek için navigator.userActivation nesnesinin hasBeenActive (kalıcı) ve isActive (geçici) özellikleri vardır; destek için MDN uyumluluk tablosuna bakın. Pano örnekleri Clipboard API yazısında.
const dugme = document.querySelector('#kopyala');
dugme.addEventListener('click', async () => {
// tıklamanın sağladığı geçici etkinlik içinde çağrılıyor
try {
await navigator.clipboard.writeText('kopyalanacak metin');
} catch (hata) {
if (hata.name === 'NotAllowedError') {
// izin yok ya da etkinlik süresi dolmuş
}
}
});Örnek: hataları kullanıcı mesajına çevirmek
Uygulamanın her yerinde aynı ayrımı tekrar yazmak yerine hata adını tek bir yerde kullanıcıya gösterilecek metne çeviren bir yardımcı işinizi kolaylaştırır. Aşağıdaki fonksiyon DOMException adlarına göre mesaj seçer, AbortError için mesaj göstermez, TypeError'ı ağ ya da istek hatası olarak ele alır ve tanımadığı her şeyi yeniden fırlatır. Örnekteki hatalar elle oluşturuldu; kod tarayıcıda da Node.js'te de aynı çıktıyı verir.
function kullaniciMesaji(hata) {
if (hata instanceof DOMException) {
switch (hata.name) {
case 'NotAllowedError': return 'İzin verilmedi veya işlem bu bağlamda yapılamaz.';
case 'SecurityError': return 'Güvenlik kısıtı: sayfa HTTPS üzerinden mi açılıyor?';
case 'AbortError': return null; // kullanıcı ya da kod iptal etti, mesaj gösterme
case 'TimeoutError': return 'İşlem zaman aşımına uğradı, tekrar deneyin.';
case 'QuotaExceededError': return 'Depolama alanı doldu.';
case 'NotFoundError': return 'İstenen öğe ya da cihaz bulunamadı.';
case 'NotSupportedError': return 'Bu tarayıcı bu işlemi desteklemiyor.';
case 'InvalidStateError': return 'Nesne bu işlem için uygun durumda değil.';
default: return 'Beklenmeyen hata: ' + hata.name;
}
}
if (hata instanceof TypeError) return 'Ağ hatası ya da geçersiz istek.';
throw hata;
}
const ornekler = [
new DOMException('', 'NotAllowedError'),
new DOMException('', 'AbortError'),
new DOMException('', 'TimeoutError'),
new DOMException('', 'DataCloneError'),
new TypeError('Failed to fetch'),
];
for (const h of ornekler) console.log(JSON.stringify(kullaniciMesaji(h)));
// "İzin verilmedi veya işlem bu bağlamda yapılamaz."
// null
// "İşlem zaman aşımına uğradı, tekrar deneyin."
// "Beklenmeyen hata: DataCloneError"
// "Ağ hatası ya da geçersiz istek."Sık yapılan hatalar
- Hata koşulunu message metnine bağlamak. "Failed to fetch" gibi metinler tarayıcıya göre değişir.
- Eski code sayılarına göre karar vermek. Yeni hata adlarının çoğunun kodu yoktur ve
0döner. - 404'ü catch bloğunda beklemek.
fetch()HTTP hata kodlarında reddedilmez;response.okkontrol edin. - Yerel ağ IP'si üzerinden HTTP ile test etmek.
localhostdışında HTTP adresleri güvenli bağlam değildir. - HTTP sayfaya HTTPS iframe gömüp çalışmasını beklemek. Üst bağlam güvenli değilse çerçeve de değildir.
- Pano veya tam ekran çağrısını tıklamadan uzakta yapmak. Geçici etkinlik süresi dolmuş ya da tüketilmiş olabilir.
- AbortError'ı kullanıcıya hata olarak göstermek. Çoğu zaman bilinçli bir iptaldir.
Sık Sorulan Sorular
DOMException ile JavaScript Error arasındaki fark nedir?
TypeError, RangeError gibi hatalar JavaScript dilinin hata türleridir; DOMException ise Web API'lerinin tanımladığı hata arayüzüdür. Bir Web API bazı durumlarda TypeError (geçersiz argüman, ağ hatası), bazılarında DOMException fırlatır; MDN sayfalarındaki Exceptions bölümü hangisinin geldiğini söyler. Dil tarafındaki hata türleri için JavaScript öğrenme rehberi serisine bakın.
localhost'ta çalışan özellik sunucuda neden çalışmıyor?
http://localhost güvenli bağlam sayılır, ama sunucunuz http:// ile yayın yapıyorsa güvenli bağlam değildir. Siteyi HTTPS'e taşıyın ve sayfadaki tüm kaynakların HTTPS ile yüklendiğinden emin olun.
NotAllowedError aldım ama kullanıcı izin vermişti, neden?
MDN'e göre aynı ad izin politikası engeli, çapraz kökenli iframe'de eksik allow izni, geçici kullanıcı etkinliğinin olmaması ve güvensiz bağlam gibi durumlarda da kullanılır. İlgili API sayfasının Exceptions bölümündeki maddeleri tek tek kontrol edin.
Kendi kodumda DOMException fırlatmalı mıyım?
Yapıcı herkese açıktır ve MDN örneği de özel bir DOMException fırlatır. Web API'lerine benzeyen bir kütüphane yazıyorsanız iptal için AbortError, zaman aşımı için TimeoutError kullanmak, çağıranların bu durumları tanıdık adlarla ayırt etmesini sağlar.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Web API öğrenme rehberi · CORS hataları ve çözümleri · Fetch API kullanımı · HTTPS ve TLS rehberi · Karma içerik hatası · Clipboard API · getUserMedia ile kamera erişimi