Skip to content
Debugging

Unexpected Token in JSON at Position 0: What It Means and How to Fix It

·8 min read
Unexpected Token in JSON at Position 0: What It Means and How to Fix It - Debugging guide from JSON Prettifier

Quick answer: Unexpected token ... in JSON at position 0 means the text handed to JSON.parse() is not JSON at all; it fails on the very first character. That character names the cause: < means the server returned HTML, u means you parsed undefined, o means you parsed an object ([object Object]),  means the file has a byte order mark, and ' means single quotes. Log the raw text before parsing and the fix is usually obvious.

This error does not tell you that your JSON has a typo somewhere. It tells you that whatever you parsed never was JSON. Position 0 is the giveaway: a document with a stray comma fails at position 847, not at the first byte. So the job is not to proofread the JSON. The job is to find out what text you actually received, and the token in the message has already done half the work.

Repair a copy of the failing payload with the JSON Fixer, then review the changes before using the result.

Read the Token, Not the Position

The message has two variants depending on the JavaScript engine version. Older V8 (Chrome, Edge, Node) prints the short form; newer V8 prints a snippet of the input, which is a big improvement:

// Older form
SyntaxError: Unexpected token < in JSON at position 0

// Newer form
SyntaxError: Unexpected token '<', "<!DOCTYPE " is not valid JSON

// Firefox
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

Whichever form you see, the first character after "token" maps to a cause:

TokenWhat you parsedWhere it came from
<HTML page instead of JSONLogin redirect, 404 page, proxy error, wrong URL
uThe string "undefined"JSON.parse(undefined), missing variable, empty storage key
oThe string "[object Object]"Object passed where a JSON string was expected
\ufeffUTF-8 byte order markFile saved by Notepad, PowerShell, or Excel
'Single-quoted JSONHand-written JSON or a Python dict printed with str()
NThe word NaN or null-ish textJSON.parse(NaN) or a number that failed to compute
/A commentConfig file with // or /* */ comments
}or ] : trailing comma before itHand-edited file; the position is usually not 0

The sections below take the five common ones in turn: how to confirm, then how to fix.

Token <: The Server Sent HTML

By a wide margin the most frequent case. Your code called an API and got a web page. The < is the start of <!DOCTYPE html> or <html>.

Confirm it

Open the browser DevTools Network tab, click the request, and look at the Response tab. You will see the page. Common pages that show up here:

  • A login page: the session or token expired, and the server redirected to sign-in with a 200 status.
  • A 404 page: the URL is wrong. A typo in the path, a missing /api prefix, or a dev server that serves index.html for every unknown route (the single-page app fallback) are the classics.
  • A 502 or 504 page from nginx, Cloudflare, or a load balancer, meaning the API behind it was down.
  • A captive portal or corporate proxy page, if the user is on hotel or office Wi-Fi.

In code, replace the parse with a text read while you investigate:

const res = await fetch("/api/items");
const text = await res.text();
console.log(res.status, res.headers.get("content-type"));
console.log(text.slice(0, 200));

Fix it

Fix the underlying cause (the URL, the auth, the proxy), then make the client refuse to parse non-JSON so the next occurrence produces a clear error instead of this one:

const res = await fetch("/api/items");
const type = res.headers.get("content-type") || "";
if (!res.ok || !type.includes("application/json")) {
  throw new Error("Expected JSON, got " + res.status + " " + type);
}
const items = await res.json();

The fetch JSON guide builds this into a reusable helper with timeouts and retries.

Token u: You Parsed undefined

JSON.parse(undefined) coerces its argument to the string "undefined" and fails on the u. Nothing was fetched or read; the variable simply had no value.

const saved = localStorage.getItem("cart");   // null if never set
JSON.parse(saved);                              // null parses fine, returns null

const settings = {};
JSON.parse(settings.theme);                     // undefined -> Unexpected token u

Note the asymmetry: JSON.parse(null) works, because String(null) is "null", which is valid JSON. undefined has no such luck.

Confirm it

console.log(typeof value, value) right before the parse. If it prints undefined undefined, trace where the value should have been assigned: a misspelled property name, a function that forgot to return, an async result used before it resolved.

Fix it

const raw = localStorage.getItem("cart");
const cart = raw ? JSON.parse(raw) : [];

Guard the parse, and fix the source so the value exists. If the raw value is an empty string rather thanundefined, you get a different message, Unexpected end of JSON input, with the same guard as the fix.

Token o: You Parsed an Object

This one usually reports position 1, not 0, and that detail is diagnostic. JSON.parse(someObject) coerces the object to "[object Object]". The parser reads [ as the start of an array, then hits o and stops.

const user = { name: "Ada" };
JSON.parse(user);
// SyntaxError: Unexpected token o in JSON at position 1
// newer: Unexpected token 'o', "[object Object]" is not valid JSON

Confirm it

The data is already parsed. This happens when a library (Axios, a fetch wrapper, a message bus) has parsed the response for you and your code parses it again, or when you JSON.parse a value that was never stringified in the first place.

Fix it

Delete the JSON.parse. If you need to tolerate both forms (some callers pass strings, some pass objects), check first:

const data = typeof input === "string" ? JSON.parse(input) : input;

The same mistake in the other direction, sending an object as a request body without JSON.stringify, puts the literal text [object Object] on the wire and gives the server this error instead of you.

Token : A Byte Order Mark

The token is invisible. The message will show either  or, in some engines, an empty pair of quotes with nothing between them. The file begins with the three bytes EF BB BF, a UTF-8 byte order mark that the JSON spec says must not be present and that JSON.parse will not skip.

Confirm it

console.log(text.charCodeAt(0));      // 65279 means BOM
console.log(JSON.stringify(text.slice(0, 5)));   // "\ufeff{\"id" makes it visible

On the command line, xxd file.json | head -1 shows efbb bf7b at the start. The usual sources are Windows Notepad in older versions, PowerShell's Out-File and > redirection, and Excel's CSV export when a CSV was converted to JSON.

Fix it

// At read time
const clean = text.replace(/^\uFEFF/, "");
const data = JSON.parse(clean);

// In Python, let the codec strip it
with open("file.json", encoding="utf-8-sig") as f:
    data = json.load(f)

Then fix the file at the source: in VS Code the encoding indicator in the status bar says "UTF-8 with BOM"; click it and choose "Save with Encoding" then plain UTF-8. The UTF-8 and BOM guide covers the other places it hides.

Token ': Single Quotes

JSON strings and keys must use double quotes. {'name': 'Ada'} is a valid JavaScript object literal and a valid Python dict, and invalid JSON. The parser fails on the first ' after the brace, so the position is 1 rather than 0 if there is no leading whitespace.

Confirm it

Look at the text. If it was produced by printing a Python dict with print(d) or str(d), that is the cause; Python's repr uses single quotes and writes True and None, neither of which is JSON either.

Fix it

Produce the text with a real serializer: json.dumps(d) in Python, JSON.stringify(obj) in JavaScript. Do not fix it with .replace(/'/g, '"'); that breaks any value containing an apostrophe. If you have a one-off file to repair, paste it into JSON Prettifier, which points at the first offending quote so you can correct the file by hand, then validate again.

Less Common Tokens

  • Token N: the text is NaN, usually from JSON.parse(someNumber) where the arithmetic failed. JSON has no NaN, Infinity, or undefined; only finite decimal numbers are valid.
  • Token /: a comment at the top of the file. JSON forbids comments; see comments in JSON for the alternatives and the parsers that allow them anyway.
  • Token } or ] at a high position: a trailing comma just before the closing bracket. That is not a position-0 problem; it is a syntax slip inside otherwise valid JSON, and the fix is to delete the comma.
  • Token a, e, i and other letters: often the start of an unquoted key or value such as {id: 1}, or a plain-text error message like error: not found returned by a server that forgot to set JSON.

A Debugging Checklist

  1. Read the token in the message. Match it against the table above.
  2. Log the input before the parse, wrapped in JSON.stringify() so invisible characters show.
  3. For network responses, check status and Content-Type in the Network tab. HTML means the request, not the parser, is the problem.
  4. If the input looks like JSON but still fails, paste it into a validator to get the real line and column. Position 0 errors in such cases are almost always a BOM.
  5. Add a guard so that the next failure produces an error that names the cause (status code, content type, missing value) rather than a token.

If your error has a large position number instead of 0 or 1, you have a different problem: valid JSON with a mistake in the middle. The general JSON parse error guide and the list of common JSON errors cover those.

Frequently Asked Questions

What does 'Unexpected token < in JSON at position 0' mean?
The text you parsed starts with a < character, which means it is HTML, not JSON. The server returned a web page, typically a login page, a 404 page, or a proxy error page, while your code expected an API response. Log the raw text or check the Network tab to see which page it was.
What does 'Unexpected token u in JSON at position 0' mean?
You passed undefined to JSON.parse. The value is coerced to the string 'undefined', and the parser fails on the first letter. The usual sources are a variable that was never assigned, a missing property, or an empty localStorage key read without a null check.
What does 'Unexpected token o in JSON at position 1' mean?
You passed an object to JSON.parse. It is coerced to the string '[object Object]'; the parser accepts the opening [ as the start of an array and then fails at position 1 on the letter o. The data is already parsed, so remove the JSON.parse call.
Why is position 0 mentioned so often in this error?
Position 0 is the very first character, and a parse that fails there means the entire input is the wrong kind of text, not JSON with a small mistake inside it. That is why the first character is enough to identify the cause in most cases.
How do I see what text JSON.parse actually received?
Log it before parsing, for example console.log(JSON.stringify(text.slice(0, 80))). Wrapping it in JSON.stringify makes invisible characters such as a BOM (\ufeff) or stray whitespace visible. For fetch, use response.text() instead of response.json() while debugging.
Does the error message look different in newer browsers?
Yes. Recent versions of Chrome, Edge, and Node print a longer form such as Unexpected token '<', "<!DOCTYPE "... is not valid JSON, which shows a snippet of the input. Firefox says JSON.parse: unexpected character at line 1 column 1. The cause and fix are the same.

Not Sure What You Received? Paste It

Drop the raw response or file into the validator and see instantly whether it is JSON, and if not, exactly where it stops being JSON. Nothing is uploaded.

Validate JSON Now