JavaScript hata mesajları üç parçadan oluşur: hata tipi (TypeError, ReferenceError, SyntaxError, RangeError), motorun ürettiği açıklama ve hatanın oluştuğu satır. En sık gördüğünüz mesajların neredeyse hepsi birkaç kök nedene dayanır: var olmayan bir şeyi fonksiyon gibi çağırmak, undefined üzerinde özellik okumak, tanımsız bir isim kullanmak, const değişkene yeniden atama yapmak, sözdizimi hatası, async olmayan yerde await ve sonu gelmeyen özyineleme. Bu yazıda her birinin nedenini ve çözümünü, Node.js 24 ile çalıştırılmış örneklerle görüyorsunuz.
Mesaj metinleri motora göre değişir. MDN her hata sayfasında V8 (Chrome, Node.js), Firefox ve Safari karşılıklarını ayrı ayrı listeler. Örneğin aynı durum Node.js'te Cannot read properties of undefined (reading 'x'), Safari'de undefined is not an object olarak görünür. Aşağıdaki tabloda MDN'deki sayfa adını ve aynı hatanın Node.js 24'te birebir nasıl yazıldığını yan yana bulabilirsiniz.
Hata mesajları özet tablosu
| Durum | Node.js 24 mesajı | Tip |
|---|---|---|
| Fonksiyon olmayan değeri çağırmak | obj.map is not a function | TypeError |
| undefined veya null üzerinde özellik okumak | Cannot read properties of undefined (reading 'sehir') | TypeError |
| Tanımlanmamış isim | kulanici is not defined | ReferenceError |
| const değişkene yeniden atama | Assignment to constant variable. | TypeError |
| Beklenmeyen karakter veya sözcük | Unexpected token '<' / Unexpected identifier 'y' | SyntaxError |
| async dışında await | await is only valid in async functions and the top level bodies of modules | SyntaxError |
| Sonsuz özyineleme | Maximum call stack size exceeded | RangeError |
TypeError: "x" is not a function

Bir değerin arkasına () koyduğunuzda motor o değerin fonksiyon olmasını bekler. Değer undefined, sayı, dizi olmayan bir nesne ya da yanlış yazılmış bir metot adıysa bu hata gelir. En yaygın üç neden: metot adında yazım hatası, metodu yanlış tipte bir değer üzerinde çağırmak (düz nesnede map yoktur) ve bir özelliğin aynı adlı metodu gölgelemesi.
const ayarlar = { tema: "koyu", dil: "tr" };
ayarlar.map((x) => x);
// TypeError: ayarlar.map is not a function
// Çözüm: önce diziye çevirin
console.log(Object.entries(ayarlar).map(([k, v]) => `${k}=${v}`));
// [ 'tema=koyu', 'dil=tr' ]Aşağıdaki örnekte sınıfın ad metodu prototipte durur, ama constructor içinde nesneye aynı adla bir metin özelliği eklenir. Nesnenin kendi özelliği prototiptekinden önce bulunduğu için k.ad artık bir metindir. Çözüm, veri ve metot için farklı adlar kullanmaktır.
class Kopek {
constructor() { this.ad = "Karabaş"; }
ad(yeni) { this.ad = yeni; }
}
const k = new Kopek();
k.ad("Pamuk");
// TypeError: k.ad is not a functionTypeError: Cannot read properties of undefined
MDN bu hatayı "x is (not) y" sayfasında anlatır: beklenmeyen bir tip, çoğunlukla undefined ya da null. Zincirdeki ara bir adım boş geldiğinde, onun üzerinden bir sonraki özelliği okumaya çalışırsınız. Mesajdaki parantez içi (reading 'sehir') okunmaya çalışılan özelliği söyler; boş olan değer ise ondan bir önceki adımdır.
const siparis = { musteri: { ad: "Ayşe" } };
console.log(siparis.teslimat.sehir);
// TypeError: Cannot read properties of undefined (reading 'sehir')
console.log(siparis.teslimat?.sehir); // undefined
console.log(siparis.teslimat?.sehir ?? "Şehir girilmedi"); // Şehir girilmediÇözüm iki adımlıdır. Önce verinin neden boş geldiğini bulun: API yanıtı mı değişti, dizi boş mu, asenkron veri henüz gelmeden mi okundu? Alanın gerçekten isteğe bağlı olduğundan eminseniz ?. ve ?? ile güvenli okuma yapın. Bu operatörlerin ayrıntısı için optional chaining ve nullish coalescing yazısına bakabilirsiniz.
ReferenceError: "x" is not defined

Kod hiçbir kapsamda bulunmayan bir isme başvurduğunda motor ReferenceError fırlatır. Nedenler genellikle yazım hatası, değişkeni başka bir fonksiyonun içinde tanımlayıp dışarıda kullanmak ya da bir kütüphanenin henüz yüklenmemiş olmasıdır.
const kullanici = "Deniz";
console.log(kulanici);
// ReferenceError: kulanici is not defined
console.log(typeof tanimsizDegisken); // undefinedtypeof tanımsız isimlerde hata fırlatmaz, "undefined" döndürür; bu yüzden bir global değişkenin varlığını denetlemek için kullanılabilir. Benzer görünen ama farklı bir hata da Cannot access 'x' before initialization mesajıdır: isim vardır ama let/const satırına henüz gelinmemiştir. Bu durumun nedeni hoisting ve temporal dead zone yazısında anlatılıyor, kapsam kuralları için scope rehberine bakabilirsiniz.
TypeError: Assignment to constant variable.
Bu, V8'in mesajıdır; Firefox aynı durumu invalid assignment to const olarak yazar. const ile tanımlanan bir değişkene ikinci kez değer atadığınızda oluşur. Önemli nokta: const değişkenin bağlantısını sabitler, içindeki nesneyi değil. Diziye eleman eklemek ya da nesnenin özelliğini değiştirmek serbesttir.
const LIMIT = 10;
LIMIT = 20;
// TypeError: Assignment to constant variable.
const sepet = [];
sepet.push("kalem"); // hata yok
console.log(sepet); // [ 'kalem' ]Değeri gerçekten değişecekse let kullanın; sabit kalması gerekiyorsa farklı bir isimle yeni bir const tanımlayın. Ayrıntılar var, let ve const farkı yazısında.
SyntaxError: Unexpected token
Sözdizimi hataları kod çalışmaya başlamadan, ayrıştırma (parse) aşamasında oluşur. V8 hatanın türüne göre farklı mesajlar üretir: Unexpected token ';', Unexpected identifier 'y', Unexpected number, Unexpected string gibi. Hatanın gösterildiği yer çoğu zaman asıl sorunun hemen sonrasıdır; bir önceki satırı da kontrol edin.
const ayar = {
x: 1
y: 2
};
// SyntaxError: Unexpected identifier 'y' (x: 1 satırının sonunda virgül eksik)Günlük hayatta en çok karşılaşılan biçimi JSON.parse kaynaklıdır. Sunucudan JSON beklerken bir HTML hata sayfası gelirse ilk karakter < olur ve ayrıştırma ilk adımda durur. Boş yanıt Unexpected end of JSON input, tek tırnaklı anahtarlar ise başka bir mesaj üretir.
JSON.parse("<!DOCTYPE html><html>...");
// SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
JSON.parse("");
// SyntaxError: Unexpected end of JSON input
JSON.parse("{'ad': 'Ali'}");
// SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2)JSON hatalarını ayıklarken ham yanıtı ve HTTP durum kodunu loglayın. Geçerli JSON kuralları için JSON.parse ve JSON.stringify rehberine bakabilirsiniz.
SyntaxError: await is only valid in async functions
await yalnızca async fonksiyonların, async generator'ların ve modüllerin üst düzeyinde kullanılabilir. Node.js 24'ün mesajı await is only valid in async functions and the top level bodies of modules şeklindedir. En sık yapılan hata, async bir fonksiyonun içinde olduğunuz halde forEach gibi bir metoda verdiğiniz normal callback'in içinde await kullanmaktır; callback ayrı bir fonksiyondur.
urunIdleri.forEach((id) => {
await getir(id);
});
// SyntaxError: await is only valid in async functions and the top level bodies of modulesSırayla çalışması gereken işler için for...of, paralel çalışabilecek işler için Promise.all ile async callback kullanın:
const bekle = (ms, d) => new Promise((r) => setTimeout(() => r(d), ms));
async function sirayla(idler) {
const sonuc = [];
for (const id of idler) {
sonuc.push(await bekle(10, id * 2));
}
return sonuc;
}
async function paralel(idler) {
return Promise.all(idler.map(async (id) => bekle(10, id * 2)));
}
sirayla([1, 2, 3]).then(console.log); // [ 2, 4, 6 ]
paralel([1, 2, 3]).then(console.log); // [ 2, 4, 6 ]Dosyanın en üstünde await kullanmak istiyorsanız dosyanın modül olması gerekir. Node.js'te .mjs uzantılı dosyalar modül olarak yüklenir. Konunun tamamı async/await rehberinde ve ES modülleri yazısında anlatılıyor.
RangeError: Maximum call stack size exceeded
Her fonksiyon çağrısı çağrı yığınına bir kayıt ekler. Bir fonksiyon kendini durma koşulu olmadan çağırırsa yığın dolar ve motor RangeError fırlatır. Çözüm her zaman bir taban durumu (base case) eklemektir.
function faktoriyel(n) {
return n * faktoriyel(n - 1); // durma koşulu yok
}
faktoriyel(5);
// RangeError: Maximum call stack size exceeded
function faktoriyel2(n) {
if (n <= 1) return 1;
return n * faktoriyel2(n - 1);
}
console.log(faktoriyel2(5)); // 120Daha sinsi bir neden, kendi adını atayan setter'dır. set ad() içinde this.ad = deger yazdığınızda atama yine setter'ı çağırır ve döngü sonsuza gider. Değeri farklı bir alanda, tercihen özel bir alanda tutun:
class Kisi {
set ad(deger) { this.ad = deger; } // kendini çağırır
}
new Kisi().ad = "Ece";
// RangeError: Maximum call stack size exceeded
class Kisi2 {
#ad = "";
set ad(deger) { this.#ad = deger.trim(); }
get ad() { return this.#ad; }
}
const ki = new Kisi2();
ki.ad = " Ece ";
console.log(ki.ad); // EceSık yapılan hatalar ve hata ayıklama alışkanlıkları

- Mesajın yalnızca ilk satırını değil, yığın izindeki (stack trace) ilk kendi dosyanızı okuyun; hatanın gerçekten başladığı yer orasıdır.
- Hata tipine bakın:
SyntaxErrorkod hiç çalışmadan,TypeErrorveReferenceErrorçalışma anında oluşur. - Hataları
try...catchile yakalayıpe.namevee.messagedeğerlerini loglayın; boş bircatchbloğu sorunu saklar. - Strict mode bazı sessiz hataları görünür hale getirir; tanımsız değişkene atama gibi durumlar için strict mode yazısına bakın.
Hata yakalama yapısının tamamı için try...catch ile hata yönetimi yazısını okuyabilirsiniz.
Sık Sorulan Sorular
Aynı hata neden tarayıcıda ve Node.js'te farklı yazıyor?
Mesaj metinleri standartta tanımlı değildir; her motor kendi metnini üretir. Chrome ve Node.js aynı motoru (V8) kullandığı için mesajları aynıdır, Firefox ve Safari farklı yazar. Hata tipi (TypeError gibi) ise çoğu durumda aynıdır.
"Cannot read properties of null" ile "undefined" arasında fark var mı?
Neden aynıdır, yalnızca boş gelen değer farklıdır. null genellikle bilinçli olarak "değer yok" demek için atanır (örneğin bulunamayan bir kayıt), undefined ise hiç atanmamış bir alanı gösterir.
Kodum doğru görünüyor ama Unexpected token alıyorum, neden?
Asıl hata genellikle gösterilen yerden önce, örneğin eksik bir virgül, kapanmamış parantez ya da süslü parantez olarak durur. JSON ayrıştırırken alıyorsanız, gelen metnin JSON olmadığını, çoğu zaman bir HTML sayfası olduğunu kontrol edin.
Çağrı yığını sınırını artırabilir miyim?
Asıl çözüm durma koşulunu düzeltmek ya da derin özyinelemeyi döngüye çevirmektir. Sınırın kendisi motorun ayarıdır ve dil tarafından tanımlanmaz; buna güvenmek taşınabilir bir çözüm değildir.
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: JavaScript öğrenme rehberi · try...catch ile hata yönetimi · Optional chaining · Hoisting ve TDZ · Node.js nedir