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

DurumNode.js 24 mesajıTip
Fonksiyon olmayan değeri çağırmakobj.map is not a functionTypeError
undefined veya null üzerinde özellik okumakCannot read properties of undefined (reading 'sehir')TypeError
Tanımlanmamış isimkulanici is not definedReferenceError
const değişkene yeniden atamaAssignment to constant variable.TypeError
Beklenmeyen karakter veya sözcükUnexpected token '<' / Unexpected identifier 'y'SyntaxError
async dışında awaitawait is only valid in async functions and the top level bodies of modulesSyntaxError
Sonsuz özyinelemeMaximum call stack size exceededRangeError

TypeError: "x" is not a function

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.

javascript
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.

javascript
class Kopek {
  constructor() { this.ad = "Karabaş"; }
  ad(yeni) { this.ad = yeni; }
}
const k = new Kopek();
k.ad("Pamuk");
// TypeError: k.ad is not a function

TypeError: 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.

javascript
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

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.

javascript
const kullanici = "Deniz";
console.log(kulanici);
// ReferenceError: kulanici is not defined

console.log(typeof tanimsizDegisken); // undefined

typeof 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.

javascript
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.

javascript
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.

javascript
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.

javascript
urunIdleri.forEach((id) => {
  await getir(id);
});
// SyntaxError: await is only valid in async functions and the top level bodies of modules

Sırayla çalışması gereken işler için for...of, paralel çalışabilecek işler için Promise.all ile async callback kullanın:

javascript
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.

javascript
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)); // 120

Daha 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:

javascript
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); // Ece

Sık yapılan hatalar ve hata ayıklama alışkanlıkları

Sı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..., Hata tipine bakın, Hataları try...catch ile...
  • 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: SyntaxError kod hiç çalışmadan, TypeError ve ReferenceError çalışma anında oluşur.
  • Hataları try...catch ile yakalayıp e.name ve e.message değerlerini loglayın; boş bir catch bloğ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