JSON troubleshooting
JSON.parse: unexpected character at line 1 column 1 of the JSON data
Decode the Firefox JSON.parse error: what the first character means, how line and column are counted, and the Chrome, Safari and Node wording for the same input.
What the error means
This is Firefox's wording for a JSON.parse failure. Line 1 column 1 means the very first character cannot start a JSON value. A value can only start with {, [, a double quote, a digit, a minus sign, or the first letter of true, false or null. So the text is usually not JSON at all: an HTML page, a PHP warning printed before the JSON, a plain-text error, the word undefined, or an invisible byte-order mark. Firefox counts lines and columns from 1, skips leading spaces and newlines, and reports the character it rejected.
Exact messages by runtime
Messages depend on the input and runtime version. Node and Python rows were reproduced locally. Other rows cite official documentation or source. Rows marked as fragments or templates preserve the source wording and are not complete exception transcripts. Browsers and libraries may append location details.
| Runtime | Message | Input and evidence |
|---|---|---|
| Firefox | SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data | JSON.parse("<!DOCTYPE html>")Source-derived from Firefox 158 JSONParser.cpp and its message template |
| Firefox, after a newline | SyntaxError: JSON.parse: unexpected character at line 2 column 1 of the JSON data | JSON.parse("\n<br />")Source-derived: lines and columns are counted from 1 up to the rejected character |
| Firefox, a word | SyntaxError: JSON.parse: unexpected keyword at line 1 column 1 of the JSON data | JSON.parse("not found")Source-derived: a word starting with t, f or n that is not true, false or null |
| Firefox, empty input | SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data | JSON.parse("")Source-derived from Firefox 158 JSONParser.cpp |
| Chrome, Edge, Node.js / V8 | SyntaxError: Unexpected token '<', "<!DOCTYPE html>" is not valid JSON | JSON.parse("<!DOCTYPE html>")Reproduced in Node.js 24.21.0 |
| Safari / JavaScriptCore | JSON Parse error: Unrecognized token '<' | The same inputJavaScriptCore source (WebKit tag webkitgtk-2.54.1) with the JSON Parse error prefix |
| V8, byte-order mark | SyntaxError: Unexpected token '', "{"a":1}" is not valid JSON | JSON.parse("\uFEFF{\"a\":1}"); the quoted token is an invisible U+FEFFReproduced in Node.js 24.21.0 |
| Python, byte-order mark | json.decoder.JSONDecodeError: Unexpected UTF-8 BOM (decode using utf-8-sig): line 1 column 1 (char 0) | json.loads('\ufeff{"a":1}')Reproduced in Python 3.14.4 |
Causes you can reproduce
A < starts an HTML page or a PHP warning
A login page, an error page or a PHP notice printed with display_errors on starts with <. If a newline comes first, Firefox reports line 2 column 1 instead. The HTML-response guide shows how to find which request returned it.
const body = '<br />\n<b>Warning</b>: Undefined variable $id';
JSON.parse(body);
// Firefox: JSON.parse: unexpected character at line 1 column 1 of the JSON dataA letter starts plain text or undefined
Text such as Internal Server Error, or the string undefined, starts with a letter that cannot begin a value. A word starting with n, t or f, such as not found, gives unexpected keyword in Firefox.
JSON.parse('Internal Server Error');
// Node: Unexpected token 'I', "Internal S"... is not valid JSONAn invisible byte-order mark comes first
In Node.js, fs.readFileSync(path, "utf8") keeps a UTF-8 BOM as the character U+FEFF, and JSON.parse rejects it. In browsers, response.text() and response.json() remove a leading UTF-8 BOM, so this cause is rarer there.
import { readFileSync, writeFileSync } from 'node:fs';
writeFileSync('bom.json', '\uFEFF{"a":1}');
JSON.parse(readFileSync('bom.json', 'utf8'));
// SyntaxError: Unexpected token ... is not valid JSON (the token is U+FEFF)How to fix it
- Look at the raw text. In DevTools, open the failing request in the Network panel and check its status, Content-Type and response body.
- Make invisible characters visible by logging JSON.stringify(text.slice(0, 80)). A byte-order mark shows as \ufeff, and HTML or a PHP warning shows its first tag.
- Use the first character: < means HTML, a letter means plain text or undefined, and \ufeff means a byte-order mark. An empty body gives unexpected end of data instead.
- Fix the source: the URL, the session, the server error or the PHP warning. If the column is greater than 1, the text starts as JSON and breaks later, so match the rest of the message to the related guides.
Read the body once and report what arrived
The error message then shows the first characters, with invisible ones escaped, instead of a bare position.
async function readJson(response) {
const text = await response.text();
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${JSON.stringify(text.slice(0, 80))}`);
}
try {
return JSON.parse(text);
} catch (error) {
throw new Error(`Expected JSON, got ${JSON.stringify(text.slice(0, 80))}`, { cause: error });
}
}Remove one byte-order mark from a file in Node.js
Strip only a leading U+FEFF, and only where you read the file.
import { readFileSync } from 'node:fs';
const raw = readFileSync('bom.json', 'utf8');
const text = raw.charCodeAt(0) === 0xfeff ? raw.slice(1) : raw;
console.log(JSON.parse(text)); // { a: 1 }Find the exact position with Tool Kumar
- Copy the exact input text, including its original whitespace. For HTTP failures, copy the raw response body.
- Open the Tool Kumar JSON validator and paste the text. The document stays in your browser.
- Read the line and column in the error or fixable-issue banner. For an invalid document, select Go to error to move the caret to that location.
- Inspect the preceding token as well as the marked character. A parser marks where it discovered the problem; the missing quote, separator or value can start earlier.
Python character offsets are zero-based, while its displayed lines and columns are one-based. V8 string positions count UTF-16 code units; Go offsets count bytes read. Unicode text can make these offsets differ. Use the original text and its line/column context rather than copying an offset between runtimes.
Tool Kumar can classify some input as fixable loose JSON. Review a proposed change before using the JSON repair tool, then validate the result against your API contract. For empty input, inspect the producer or response because there is no character to select.
Frequently asked questions
Is this error specific to Firefox?
The wording is. Chrome, Edge and Node.js say Unexpected token followed by the character, and Safari says JSON Parse error: Unrecognized token. The input and the fix are the same.
Why line 1 column 1 when the response looks like JSON?
You may be looking at a different request, or the JSON is preceded by something you cannot see, such as a byte-order mark. Log JSON.stringify of the first characters of the exact text you pass to JSON.parse.
What does unexpected keyword mean?
The text starts with t, f or n, but the word is not true, false or null. A plain-text reply such as not found, or a typo such as nul, causes it.
What do the other Firefox JSON.parse messages mean?
expected property name or '}' points to quoting or a trailing comma. expected ',' or '}' after property value in object points to a missing comma or an unescaped quote. bad escaped character and bad control character in string literal point to string escaping. unexpected non-whitespace character after JSON data means extra data, and unexpected end of data means empty or truncated input.
Related errors and tools
- Unexpected token '<' / DOCTYPE is not valid JSON
- Unexpected end of JSON input: empty or truncated data
- "undefined" or "[object Object]" is not valid JSON
- PHP json_decode returns null: Syntax error and other causes
- Expecting ',' delimiter / Expected ',' or '}' after property value
- All JSON error guides
- JSON syntax reference
Standards and diagnostic sources
RFC 8259 and ECMA-404 define JSON syntax. Diagnostic wording belongs to the parser. The table links each cited message to its source.