Working With JSON: parse, stringify and What Breaks
Turn JSON text into data and back, read the real parse error messages, and see what stringify quietly drops or changes. After this, a bad response gets caught instead of crashing the page.
Course content
Sign in to save your progress.
-
Set Up Projects That Don't Break Each Other
-
Node.js and npm: Running JavaScript Outside the Browser
-
package.json and Lock Files: Same Install Every Time
-
-
-
Organize Code Other People Can Read
-
JavaScript Modules: import, export and Splitting One Big File
-
JavaScript Classes: When an Object Literal Is No Longer Enough
-
Destructuring and Spread Without the Confusion
-
-
-
Work With Real Data
-
Array Methods: map, filter, reduce and When a Loop Is Clearer
-
Working With JSON: parse, stringify and What Breaks
-
Dates in JavaScript Without Losing a Day
-
-
-
Waiting for Things
-
Callbacks to Promises: Why the Code Runs Out of Order
-
async/await and fetch: Calling a Real API
-
-
-
Prove It Works Before Someone Else Finds Out
-
try/catch and Custom Errors
-
Your First Tests With Vitest
-
-
- Final Check: JavaScript Intermediate
Skip ahead: If you already know why JSON.parse throws on undefined and what JSON.stringify drops, skip to "What JSON.stringify quietly changes".
JSON is how data moves between programs: an API response, a config file, something saved in localStorage. It looks like a JavaScript object, which is the trap. It's a text format with stricter rules, and JavaScript has two functions to cross between them: JSON.parse turns text into data, JSON.stringify turns data into text. Most bugs happen at that crossing.
The rules JSON has and JavaScript doesn't
- Property names in double quotes:
{"name": "Ana"}, not{name: "Ana"}and not{'name': 'Ana'}. - Strings in double quotes.
- No trailing commas.
- No comments.
- Values: strings, numbers,
true,false,null, arrays, objects. Noundefined, no functions, no dates (dates travel as strings).
JSON.parse: text in, data out
const text = '{"id": 1042, "customer": "Ana", "paid": true, "items": ["rice", "eggs"]}';
const order = JSON.parse(text);
console.log(order.customer, order.items.length, typeof order.paid);
Ana 2 boolean
When the text breaks a rule, JSON.parse throws a SyntaxError. Here's what Node 24 (and Chrome) actually says for the common cases:
const samples = ['{name: "Ana"}', '{"a": 1,}', "", "undefined", '<!DOCTYPE html><html>'];
for (const text of samples) {
try {
JSON.parse(text);
} catch (error) {
console.log(error.message);
}
}
Expected property name or '}' in JSON at position 1 (line 1 column 2)
Expected double-quoted property name in JSON at position 8 (line 1 column 9)
Unexpected end of JSON input
"undefined" is not valid JSON
Unexpected token '<', "<!DOCTYPE "... is not valid JSON
Read the message for a clue to the cause:
- Expected property name: a key without double quotes. Someone wrote JavaScript, not JSON.
- Expected double-quoted property name near the end: usually a trailing comma.
- Unexpected end of JSON input: the text was empty or cut off. Often an empty response from a server.
- "undefined" is not valid JSON: you passed
undefined, usually a property that doesn't exist, likeJSON.parse(response.data)when the field is called something else. (A missinglocalStoragekey is different:getItemgivesnull, andJSON.parse(null)quietly returnsnull.) - Unexpected token '<': you got HTML, not JSON. Almost always an error page or a wrong URL.
The tutorial Fix "Unexpected token in JSON" Errors goes through how to find which one you have.
⚠ Warning: Wrap JSON.parse in try/catch whenever the text comes from outside your code: a server, a file, a user, localStorage. You don't control that text. One bad response shouldn't take down the whole page.
JSON.stringify: data in, text out
const order = { id: 1042, customer: "Ana", items: ["rice"] };
console.log(JSON.stringify(order));
console.log(JSON.stringify(order, null, 2));
{"id":1042,"customer":"Ana","items":["rice"]}
{
"id": 1042,
"customer": "Ana",
"items": [
"rice"
]
}
The third argument indents it for humans. Use it for logs and files you'll read, not for data you send.
What JSON.stringify quietly changes
This is the part that doesn't throw. It just loses data.
const order = {
id: 1042,
note: undefined,
print: () => "hi",
discount: NaN,
createdAt: new Date(Date.UTC(2026, 9, 15, 8, 30)),
};
const copy = JSON.parse(JSON.stringify(order));
console.log(copy);
console.log(typeof copy.createdAt);
{ id: 1042, discount: null, createdAt: '2026-10-15T08:30:00.000Z' }
string
undefinedand functions: gone.NaNandInfinity: becomenull.- Dates: become strings. Parse them back on purpose with
new Date(copy.createdAt). - Class instances: become plain objects, without their methods or private fields.
And two things that do throw: BigInt values (TypeError: Do not know how to serialize a BigInt) and objects that point to themselves (TypeError: Converting circular structure to JSON).
💡 Tip: JSON.parse(JSON.stringify(x)) is an old way to deep-copy data. Because of the list above, it silently breaks dates and drops fields. Use structuredClone(x) instead. It keeps dates as dates.
Common mistakes
- Parsing something that's already an object.
JSON.parse({})turns it into the text[object Object]first and throws"[object Object]" is not valid JSON. - Building JSON by gluing strings together. One quote in a name breaks it. Use
JSON.stringify. - Expecting
createdAtto still be a Date after a round trip. - Not catching parse errors from a server.
- Storing numbers like order IDs that are too big for JavaScript numbers (above 9007199254740991) as numbers. Send them as strings.
What happens if you skip this
Nothing, for a while. Then the server returns an error page instead of JSON, JSON.parse throws on the first <, and your whole page stops with a message nobody on your team has seen before. Or a date comes back as a string, order.createdAt.getFullYear() throws, and you spend an hour on a bug that was a single missing new Date().
What do you get from JSON.stringify({ a: undefined, b: null })? Try it.
About
Turn JSON text into data and back, read the real parse error messages, and see what stringify quietly drops or changes. After this, a bad response gets caught instead of crashing the page.
- Duration
- 5 min
- Last update
- 08/26/2026
Comments (0)
Sign in to commentNo comments yet.