/errors/json/unexpected-token-not-valid-json
SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated 2026-10-20
- tool
- JSON
- exit code
- 1
- versions
- Node.js 20+
- os
- any
JSON.parse (and response.json()) throws SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON when the text it receives is HTML instead of JSON. The < is the first character of <!DOCTYPE html>. The request reached a web page (an error page, a login page, or your dev server's index.html), not the API you expected.
Reproduce the error
node -e 'JSON.parse("<!DOCTYPE html><html><body>Not Found</body></html>")' 2>&1 | grep SyntaxError; exit "${PIPESTATUS[0]}"Output · exit 1
SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
Related messages from the same parser
node -e '
for (const text of ["", "{\"a\": 1,}", "{a: 1}"]) {
try { JSON.parse(text); } catch (e) { console.log(JSON.stringify(text).padEnd(14), "->", e.message); }
}'Output
"" -> Unexpected end of JSON input
"{\"a\": 1,}" -> Expected double-quoted property name in JSON at position 8 (line 1 column 9)
"{a: 1}" -> Expected property name or '}' in JSON at position 1 (line 1 column 2)Fix: check the response before parsing
const res = await fetch('/api/items');
const type = res.headers.get('content-type') ?? '';
if (!res.ok || !type.includes('application/json')) {
const body = await res.text();
throw new Error(`Expected JSON, got ${res.status} ${type}: ${body.slice(0, 80)}`);
}
const data = await res.json();The error then tells you the real status code and shows the start of the HTML, which usually names the problem (404, 401, 502).
Sources
Related pages
errors · dnsError: getaddrinfo ENOTFOUND (DNS lookup failed)Node.js throws getaddrinfo ENOTFOUND when DNS cannot resolve the host: a typo, a full URL passed as host, a name only in /etc/hosts, or no working DNS.codes · httpHTTP status codes: 1xx to 5xx with meaning and common causesHTTP status codes explained: 200 and 204, the redirects 301 to 308, client errors 400 to 429 and server errors 500 to 504, each with its most common cause.compare · yamlJSON vs YAML vs TOML: which format for config and dataJSON is strict and universal but has no comments, YAML is readable but its typing surprises, TOML is explicit and made for config. One data set in all three.