JavaScript “Unexpected token '<'” hatası, çoğunlukla response.json() ile JSON beklenirken sunucudan HTML biçiminde bir hata sayfası, 404 yanıtı veya yönlendirme sonucunda başka bir web sayfası geldiğinde oluşur. JSON ayrıştırıcısı yanıtın ilk karakterinde < gördüğünde bunun geçerli JSON olmadığını bildirir.
Bu nedenle sorun genellikle JavaScript sözdiziminden çok, HTTP yanıtının beklenen formatta olmamasıdır. Yalnızca hata metnine bakarak belirli bir framework ya da sunucu hakkında kesin teşhis koymak doğru değildir; önce gelen yanıtın durum kodunu, içerik türünü ve ham gövdesini incelemek gerekir.
JavaScript "Unexpected token '<'" Hatası Ne Anlama Gelir?
Geçerli bir JSON yanıtı genellikle bir nesne, dizi, metin veya sayı ile başlar. Örneğin {"name":"Ada"} bir JSON nesnesidir. HTML yanıtları ise çoğu zaman <!doctype html>, <html> ya da <body> gibi etiketlerle başladığı için hata mesajındaki < işareti, ayrıştırılmaya çalışılan içeriğin HTML olabileceğine dair güçlü bir ipucu verir.
Bu durum birkaç farklı nedenle ortaya çıkabilir: İstekte kullanılan endpoint yanlış olabilir, istenen rota bulunamadığı için 404 sayfası dönebilir, sunucu hata durumunda HTML açıklama sayfası gönderebilir veya istek beklenmedik biçimde başka bir adrese yönlenebilir. Bazı geliştirme ortamlarında frontend uygulamasının HTML giriş dosyası da API yanıtı beklenen adrese dönebilir.
Önemli nokta şudur: fetch() isteği bir HTTP yanıtı aldığı sürece 404 ya da 500 gibi durumlarda kendiliğinden hata fırlatmayabilir. Kod daha sonra bu yanıtı response.json() ile ayrıştırmaya çalıştığında “Unexpected token '<'” mesajı görülebilir. Bu yüzden JSON ayrıştırmadan önce yanıtın gerçekten JSON olup olmadığı kontrol edilmelidir.
Bu hatayı anlamaya yardımcı olacak temel yaklaşım ve benzer JavaScript sorunları için JavaScript ve web geliştirme üzerine diğer teknik yazılara göz atabilirsin.
Yanıtı Ayrıştırmadan Önce Dört Adımda Teşhis

- Durum kodunu kontrol et.
Önce
response.statusve gerekirseresponse.okdeğerlerini oku. Beklenen çıktı, isteğin hangi HTTP durum koduyla sonuçlandığını ve başarılı kabul edilip edilmediğini göstermelidir. Örneğin200başarılı bir yanıtı,404bulunamayan bir kaynağı,500ise sunucu tarafındaki bir hatayı işaret edebilir.response.okdeğeri, başarılı kabul edilen durumlardatrueolur. - Content-Type bilgisini oku.
response.headers.get('content-type')ile yanıtın bildirdiği içerik türünü kontrol et.application/jsonJSON beklentisini desteklerkentext/html, HTML sayfası geldiğini gösterir. Ancak Content-Type tek başına kesin kanıt değildir; sunucu yanlış bir başlık göndermiş olabilir. Bu nedenle sonraki adımda ham gövde de incelenmelidir. - JSON ayrıştırmadan önce ham gövdeyi incele.
await response.text()kullanarak sunucunun gerçekten ne gönderdiğini gör. İlk karakterler<!doctype html>veya<html>ise HTML yanıtı almış olabilirsin. Bir hata mesajı, giriş sayfası ya da sunucu açıklaması da endpoint sorununa işaret edebilir. Aynı yanıt gövdesini metin olarak okuduktan sonra doğrudanresponse.json()çağrılamaz; yanıt gövdesi genellikle tek kez okunur. Her iki incelemeye de ihtiyaç varsa yanıtı önceden kopyalamak gerekir. - URL, yöntem ve yönlendirme bilgilerini birlikte değerlendir.
Kullandığın URL’yi, HTTP yöntemini ve
response.urlile görülen son adresi kontrol et.response.redirecteddeğeritrueise istek başka bir adrese yönlenmiş olabilir.404iletext/htmlbirlikte görülüyorsa yanlış endpoint veya bulunamayan rota olasılığı artar.200vetext/html, frontend giriş sayfası fallback’i ya da yönlendirme sonucunu düşündürebilir.5xxvetext/htmlise sunucunun HTML hata sayfası döndürdüğünü gösterebilir. Buna karşılık2xxveapplication/jsongörülmesine rağmen ayrıştırma başarısızsa gövdenin geçerli JSON sözdizimine sahip olup olmadığı ayrıca kontrol edilmelidir.
JSON ve HTML Yanıtını Sahte Örneklerle Karşılaştırma

response.json() hatasını anlamanın en hızlı yollarından biri, sunucudan gelen gövdenin ilk karakterlerine ve yanıt başlıklarına bakmaktır. Aşağıdaki iki senaryo temsili örneklerdir:
| Yanıt türü | Sahte gövde başlangıcı | response.status | Content-Type | response.text() gözlemi | beklenen ayrıştırma sonucu |
|---|---|---|---|---|---|
| JSON yanıtı | {"ok":true} |
200 | application/json |
Metin { karakteriyle başlar. |
JSON ayrıştırması başarılı olabilir ve bir JavaScript nesnesi döner. |
| HTML hata sayfası | <!doctype html><html> |
404 | text/html |
Metin < karakteriyle başlar. |
response.json() çağrısı Unexpected token '<' hatasına yol açar. |
Bu değerler iki sahte senaryo için verilmiştir. HTML yanıt her zaman 404, JSON yanıt da her zaman 200 olmak zorunda değildir. Örneğin sunucu bir JSON hata gövdesini 400 veya 500 durum koduyla gönderebilir. Bu nedenle yalnızca response.status değerine bakmak yeterli değildir; durum kodu, Content-Type ve gövdenin gerçek içeriği birlikte değerlendirilmelidir.
response.text() ile Güvenli Fetch Kodu Nasıl Yazılır?
Gövdeyi önce response.text() ile almak, yanıtın gerçekten JSON olup olmadığını görmeni sağlar. Ayrıca yanıt gövdesi bir kez okunduktan sonra aynı gövdeyi tekrar response.json() ile okumaya çalışmak yerine, elde edilen metni JSON.parse() ile ayrıştırmak daha kontrollü bir teşhis akışı sunar.
async function fetchJson(url) {
const response = await fetch(url);
const contentType =
response.headers.get("content-type") || "belirtilmedi";
const body = await response.text();
const preview = body
.slice(0, 160)
.replace(/s+/g, " ")
.trim();
if (!response.ok) {
throw new Error(
`HTTP ${response.status} hatası. ` +
`Content-Type: ${contentType}. ` +
`Gövde önizlemesi: ${preview}`
);
}
if (!contentType.toLowerCase().includes("json")) {
throw new Error(
`JSON bekleniyordu ancak Content-Type "${contentType}". ` +
`HTTP ${response.status}. ` +
`Gövde önizlemesi: ${preview}`
);
}
try {
return JSON.parse(body);
} catch (error) {
const detail =
error instanceof Error ? error.message : "Bilinmeyen ayrıştırma hatası";
throw new Error(
`JSON ayrıştırılamadı. HTTP ${response.status}, ` +
`Content-Type: ${contentType}. ${detail} ` +
`Gövde önizlemesi: ${preview}`
);
}
}
Başarılı bir JSON yanıtında fonksiyon ayrıştırılmış nesneyi döndürür. 404 veya 5xx gibi başarısız bir HTTP yanıtında ise durum kodunu, içerik türünü ve ham gövdenin kısa bir önizlemesini içeren kontrollü bir hata oluşur. Yanıt 200 olsa bile gövde HTML ise Content-Type kontrolü JSON ayrıştırmasından önce uyarı verir.
Content-Type JSON gösterdiği hâlde gövde bozuksa hata, son JSON.parse(body) aşamasında yakalanır. Böylece hata mesajı yalnızca Unexpected token demekle kalmaz; geliştiriciye sunucunun ne döndürdüğünü incelemek için gerekli ipuçlarını da sağlar.
Yanlış Endpoint, Yönlendirme ve Sunucu Hatasını Ayıran Kontrol Listesi
Unexpected token '<' hatasını çözmek için aşağıdaki kontrol listesini istekten gelen yanıtı ayrıştırmadan önce sırayla uygula:
- İstek adresini doğrula: URL'nin API yolunu, frontend ile backend arasındaki temel adresi ve kullanılan HTTP yöntemini kontrol et. Beklenen çıktı, isteğin gerçekten API endpoint'ine gitmesidir.
- Yanıt bilgilerini kaydet:
response.status,response.urlve uygun olduğundaresponse.redirecteddeğerlerini incele. Beklenen çıktı, durum kodunun ve son yanıt adresinin tahmin ettiğin değerlerle eşleşmesidir. - Başlık ve gövdeyi birlikte kontrol et:
Content-Typedeğerini oku, ardındanresponse.text()çıktısının ilk bölümüne bak. İlk karakterler<!DOCTYPE html>veya<html>ise JSON yerine HTML geliyordur. - Durum kodunu yanıt türüyle karşılaştır:
404vetext/htmlbirlikte görülüyorsa endpoint yolunu, rota eşleşmesini ve HTTP yöntemini kontrol et.200vetext/htmldurumunda istek, API yerine frontend geliştirme sunucusunun sayfa yanıtına veya yönlendirilmiş başka bir adrese gidiyor olabilir. - Sunucu hatasını ayır:
5xxvetext/htmlalıyorsan sunucu tarafındaki hata çıktısını ve günlükleri incele. Düzeltmeden sonra beklenen başarılı durum kodunu veapplication/jsoniçerik türünü yeniden doğrula.
Fetch ve web geliştirme temellerini video formatında tekrar etmek istersen, Berk Akademi'nin video eğitimleri sayfası konuları yeniden çalışmak için kullanılabilir.
Sık Sorulan Sorular
response.ok true olduğu hâlde response.json() neden hata verebilir?
response.ok yalnızca HTTP durum kodunun başarılı aralıkta olduğunu gösterir. Yanıt gövdesi HTML, düz metin, boş içerik veya bozuk JSON ise response.json() yine hata verebilir. Bu nedenle içerik türünü ve ham gövdeyi de kontrol etmelisin.
response.text() çağırdıktan sonra neden response.json() kullanılamaz?
Fetch yanıtının gövdesi tek kullanımlık bir akış olarak tüketilir. response.text() gövdeyi okuduktan sonra response.json() için okunacak içerik kalmaz. Ham metni aldıysan gerekirse aynı içerik üzerinde ayrıca JSON.parse() kullanabilirsin.
Content-Type application/json olduğu hâlde HTML gelirse ne yapılmalıdır?
Sunucu yanlış bir içerik türü bildiriyor olabilir. Önce response.status, response.url ve response.text() çıktısını incele; ardından endpoint, yönlendirme, proxy veya sunucu yanıt başlıklarını düzelt. İstemci tarafında yalnızca başlığa güvenme.
404 ve 500 yanıtları JavaScript tarafında nasıl ayırt edilir?
response.status değerini karşılaştırarak ayırt edebilirsin. 404 istenen kaynak veya rotanın bulunamadığını, 500 ise sunucu tarafında bir hata oluştuğunu gösterir. Her iki durumda da response.ok false olur.
Bu kontrol sırasını uygulamak, JSON ayrıştırma hatasının kaynağını yanıt gövdesi, endpoint veya sunucu tarafı arasında daha hızlı ayırmanı sağlar.