Skip to content

JavaScript · browsers and Node.js

JSON Parse error: Unrecognized token '<'

JavaScriptCore, the engine in Safari and Bun, met a character that cannot start any JSON value; the < is the first character of an HTML page.

Updated · 2 min read

console
Safari, iOS, BunSyntaxError: JSON Parse error: Unrecognized token '<'
React Native (Hermes, default since 0.70)SyntaxError: JSON Parse error: Unexpected character: <
Safari, await res.json()SyntaxError: The string did not match the expected pattern.
Chrome, Edge, Node.jsSyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON

Find it in your JSON

Paste the text that failed. The checker points at the exact spot, and Repair fixes most syntax mistakes.

Input · JSON

Invalid JSON

Line 1, column 1

Unexpected '<': this looks like HTML or XML, not JSON.

1<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> ^2<html><head>

Fix: A server often sends an HTML error or login page where JSON was expected. Check the URL, the status code and the Content-Type header.

Why this happens
Invalid JSONRuns in your browser

Load from a URL

Your browser fetches it directly, so the server must allow cross-origin requests (CORS).

Why it happens

Safari, Bun and other JavaScriptCore runtimes throw JSON Parse error: Unrecognized token '<' when the text given to JSON.parse starts with a character no JSON value can start with. The token in quotes tells you what you received:

  • '<': an HTML page or XML.
  • ' ', which looks like a space: a no-break space (U+00A0) copied from a web page or a chat app.
  • '', with nothing visible between the quotes: a byte order mark (U+FEFF) at the start of the text.
  • '/': a // or /* comment.
  • '#': a # comment or a line of shell or YAML.
  • '\': JSON escaped twice, such as {\"id\": 7}.
  • '“': curly quotes from a word processor.

For '<', the server sent a web page: a 404 for a wrong URL (the Apache page in the checker above), a 5xx page from the app or a proxy, or a login page. Unexpected token ‘<’, “<!DOCTYPE “… is not valid JSON goes through each of these; the fixes are the same in every browser.

Related mistakes get their own JavaScriptCore messages: Unexpected identifier "undefined", Single quotes (') are not allowed in JSON, and Unexpected EOF for an empty string.

How to fix JSON Parse error: Unrecognized token

See what Safari received

Safari’s fetch hides the token: await res.json() rejects with The string did not match the expected pattern. and no position. Read the body as text and parse it yourself, so a failure logs what arrived:

async function getJson(url, options) {
  const res = await fetch(url, options);
  const text = await res.text();
  try {
    return JSON.parse(text);
  } catch (err) {
    console.error(`${res.status} ${res.url} ${res.headers.get('content-type')}: ${text.slice(0, 120)}`);
    throw err;
  }
}

On a Mac, the Network tab of Web Inspector (Option + Cmd + I) shows the same response.

React Native

React Native has used Hermes by default since 0.70, and Hermes words it JSON Parse error: Unexpected character: <. Apps still on JavaScriptCore print Unrecognized token '<'. In both, res.json() reads the body as text and passes it to JSON.parse, so the helper above works unchanged. Log res.url to see which host the build really called.

Bun

Bun runs on JavaScriptCore, so Bun scripts and CLI tools built with Bun print the same message. Unlike Safari, Bun’s res.json() keeps the token in its error.

Other tokens

If the token looks empty or like a space, paste the text into the JSON validator, which names invisible characters. To drop a leading byte order mark in code:

const data = JSON.parse(text.replace(/^\uFEFF/, ''));

For '/', remove the comments or use a parser that accepts them; Comments are not permitted in JSON covers the options. For '\', the producer serialized the data twice: serialize once.

Same error in other engines

All engines side by side: common JSON errors.

Questions

Does switching React Native between Hermes and JavaScriptCore fix it?

No. Both engines reject text that is not JSON; only the wording changes. Fix the response or the URL.

Why does the message have no position?

JavaScriptCore names the token but not where it is. Paste the text into the checker above to get the line and column.

Can Repair fix it?

Not for HTML: the page holds no JSON to recover. For a byte order mark, a no-break space or escaped quotes around otherwise valid JSON, Repair in the checker returns clean JSON.

Related errors

All common JSON errors

Esc