How to fix common JSON errors
Published
Most invalid JSON comes from a short list of mistakes, usually JavaScript or Python habits that JSON doesn’t allow. This guide shows how to read the parser’s error message, how to fix each common problem, and how to tell whether you are really dealing with JSON, JSON5 or JSONC.
How to read the error message
A parser reports where it gave up, which is not always where the mistake is. Take an object written over four lines: {, then "name": "Asha",, then "age": 30,, then }. Recent versions of Chrome and Node.js report something like Expected double-quoted property name in JSON at position 33 (line 4 column 1), which points at the closing brace. The real mistake is the comma at the end of line 3. Older versions word it as Unexpected token } in JSON at position 33, and Firefox ends its messages with at line 4 column 1 of the JSON data.
Position N counts characters from the start of the text, beginning at 0 and including spaces and line breaks. The JSON Formatter shows the browser’s message and, when it gives only a position, adds the line and column for you. Then look just before that point: the parser often trips on the character after the real mistake.
Two messages usually point to a problem outside the JSON itself. Unexpected token '<' at the very start usually means you received an HTML page, such as an error or login page, instead of JSON, so look at the raw response. Unexpected end of JSON input means the text is empty or stops early, for example a request that returned no body.
JavaScript habits that JSON rejects
JSON looks like JavaScript but is much stricter. These are common reasons why text that looks fine is rejected:
- Trailing commas:
[1, 2, 3,]and{"a": 1,}are errors. Delete the comma after the last item. - Single quotes:
{'name': 'Asha'}must be{"name": "Asha"}. Printing a Python dictionary instead of usingjson.dumpsproduces this, along withTrue,FalseandNonewhere JSON needstrue,falseandnull. - Unquoted keys:
{name: "Asha"}is a JavaScript object literal. JSON keys are always double-quoted strings. - Comments: neither
// notenor/* note */is allowed anywhere. - Curly quotes: “ and ” pasted from a word processor or chat app look like quotes but aren’t.
- Missing commas between items, for example after adding a line to a list. The error points at the start of the next item.
Values that don’t exist in JSON
JSON has strings, numbers, true, false, null, arrays and objects, and nothing else. NaN, Infinity and undefined are JavaScript values, and an unquoted word such as hello is an error too.
They tend to come from code that builds JSON by hand, or from Python, whose json.dumps writes NaN and Infinity by default; pass allow_nan=False to make it raise an error instead. JavaScript’s JSON.stringify goes the other way and quietly turns NaN and Infinity into null, drops object properties whose value is undefined, and writes null for undefined in arrays. Decide what a missing or invalid number should be, usually null, and write that explicitly.
Problems inside strings
A JSON string can’t contain a raw line break, tab or other control character. They must be escaped as \n, \t and so on, otherwise you get errors such as Bad control character in string literal. It typically happens when JSON is built by joining strings together. Build a normal object and serialise it with JSON.stringify or json.dumps, and the escaping is done for you.
Backslashes must be doubled. "C:\Users\asha" fails with Bad escaped character, because \U isn’t a valid escape. Worse, "C:\new\temp" is accepted without complaint and contains a line break and a tab, because \n and \t are valid escapes. Write "C:\\new\\temp".
If you’re typing JSON by hand from spreadsheet data, let a converter do it: CSV to JSON turns rows into an array of objects with every value quoted and escaped (all values come out as strings), and JSON to CSV goes the other way when you want to check an array of records in a spreadsheet.
The invisible byte order mark
If a file looks perfect but fails on its very first character, suspect a byte order mark (BOM): an invisible character, U+FEFF, that some Windows programs put at the start of UTF-8 files. Windows PowerShell 5.1, for example, adds one when you save with -Encoding UTF8. RFC 8259, the JSON standard, says a BOM must not be added to JSON sent over a network and that parsers may ignore one, but not all do. JavaScript’s JSON.parse rejects it, and Python’s json.loads reports Unexpected UTF-8 BOM (decode using utf-8-sig).
Fix it by saving the file as UTF-8 without a BOM; many editors show the encoding in the status bar and let you change it. In Python, open the file with encoding='utf-8-sig', which strips a BOM if there is one.
Duplicate keys
{"id": 1, "id": 2} is accepted by many validators. The JSON grammar doesn’t forbid repeated names; RFC 8259 only says they SHOULD be unique and notes that parsers then behave unpredictably. Many, including JavaScript’s JSON.parse and Python’s json module, keep the last value without a warning, while others reject the object or report every pair.
So a duplicate often means data silently lost in a merge or copy-paste. Formatting won’t reveal it: the JSON Formatter parses with JSON.parse, so its output just contains the last value. Search the raw text for the key name, or use a linter that reports duplicates.
Large numbers lose precision in JavaScript
JSON puts no limit on numbers, but JavaScript stores them as 64-bit floating-point values, which hold whole numbers exactly only up to 2⁵³ − 1 (9,007,199,254,740,991). Above that, JSON.parse rounds without telling you: {"id": 9007199254740993} becomes 9007199254740992. 64-bit database IDs are the usual victims, and the change is easy to miss because the last digits still look plausible.
Python parses big integers exactly, so the same JSON can work on the server and break in the browser. The reliable fix is to send such IDs as strings, such as "9007199254740993". The JSON Formatter warns you when your input contains an integer it had to round. Going the other way, JSON.stringify refuses JavaScript BigInt values with Do not know how to serialize a BigInt.
JSON, JavaScript objects, JSON5 and JSONC
A JavaScript object literal is code: it can have unquoted keys, single quotes, trailing commas, comments, functions and variables. Browser consoles also display objects in this style, so text copied from a console often isn’t valid JSON. Run JSON.stringify(obj, null, 2) to get real JSON.
JSONC (JSON with comments) is used for some configuration files, such as tsconfig.json: comments are allowed, and some tools also accept trailing commas. JSON5 goes further, allowing comments, trailing commas, single quotes, unquoted keys, hexadecimal numbers, Infinity and NaN. Both need their own parsers; a strict JSON parser, including the JSON Formatter, rejects their extra syntax.
So check what a file is meant to be before you “fix” it. A package.json must be strict JSON, while a tsconfig.json may legitimately contain comments. If you want comments in a config file, check whether the program also reads YAML, which supports them; JSON to YAML converts in both directions.
Questions
Is an empty file valid JSON?
No. A JSON text must contain exactly one value, so an empty string fails with Unexpected end of JSON input. The value doesn’t have to be an object, though: null, 42 and "hello" on their own are all valid JSON.
How can I add a note to a JSON file?
JSON has no comments, so either add an ordinary field such as "_comment": "why this is here" (only if the program reading the file ignores keys it doesn’t know), or use JSONC or YAML if that program supports them.
Why does my JSON load in Python but fail in JavaScript?
Python’s json module differs in two ways: by default it accepts NaN and Infinity, and it keeps big integers exact. JavaScript rejects the first and rounds the second. The fix in both cases is to keep the JSON strict: null instead of NaN, and long IDs as strings.
Why did my keys change order after formatting?
JavaScript objects list keys that look like whole numbers, such as "2" and "10", first and in ascending order, before all other keys. A formatter that parses with JSON.parse therefore moves them. JSON doesn’t give key order any meaning, so a program that depends on it should use an array instead.
Tools used in this guide
JSON Formatter & Validator
Validate, pretty-print or minify JSON
JSON to YAML
Convert JSON to YAML, or common YAML config files back to JSON
CSV to JSON
Convert CSV rows into a JSON array of objects
JSON to CSV
Turn a JSON array of objects into CSV for Excel or Google Sheets
This guide was drafted with the help of AI writing tools and checked against how the linked FlexyPdf tools actually work. It is general information, not professional advice. Found a mistake? Let us know.