SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON in JavaScript means you called response.json() on an API response that returned an HTML webpage (such as a 404 or 500 error page) instead of JSON data.
How do I fix SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON?
To fix SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON in JavaScript, locate the line causing the error and check the values right before it runs. Most occurrences happen because of api route returned a 404 or 500 html page. Apply a defensive check or safe fallback, make sure collections or objects exist before access, and verify return values from upstream functions.
What does SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON mean?
response.json() expects valid JSON starting with { or [. When an endpoint 404s, crashes, or redirects to a login page, the server returns an HTML document starting with <!DOCTYPE html>. JSON.parse hits the < bracket and crashes.
Why does SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON happen?
1. API route returned a 404 or 500 HTML page
res.json() is called unconditionally without checking res.ok.
Breaks
const res = await fetch("/api/users");
const data = await res.json();Works
const res = await fetch("/api/users");
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();2. Authentication redirect returned HTML login page
An unauthenticated API request gets redirected by middleware to /login.
Breaks
const res = await fetch("/api/protected");
const data = await res.json();Works
const res = await fetch("/api/protected");
const contentType = res.headers.get("content-type");
if (!contentType?.includes("application/json")) throw new Error("Expected JSON");
const data = await res.json();3. Wrong API path in Next.js or Vite
Requesting a missing API path falls through to the single-page app HTML index.
Breaks
fetch("/api/typo-route");Works
fetch("/api/correct-route");How to find it in your own code
Always check `if (!response.ok)` before parsing the response body. If an error occurs, inspect `await response.text()` to see the actual HTML response from the server.
Try it: fix this bug
easysortNumbers([10, 2, 30]) returns [10, 2, 30].
function sortNumbers(arr) {
return arr.sort();
}More challenges with this error
Each of these challenges runs into this error or pattern. Find the bug and fix it in your browser โ no install, no account needed.
Still not sure why yours breaks?
Paste it into the visualizer and watch it run line by line, with every variable at every step. Free, and it runs in your browser.