How to Parse JSON in JavaScript (JSON.parse + try/catch)

Parsing JSON in JavaScript is a single function call, JSON.parse, but doing it safely in real code means wrapping it in try/catch and knowing a handful of gotchas. This guide covers JSON.parse and JSON.stringify, handling parse errors, the optional reviver function, parsing responses from fetch, and the mistakes that produce the dreaded SyntaxError.

The basics: JSON.parse and JSON.stringify

JavaScript has a built-in global JSON object with two methods, and they are exact mirrors of each other.

// Parse: string -> object
const data = JSON.parse('{"name": "Ada", "age": 36}');
console.log(data.name);   // Ada

// Stringify: object -> string
const text = JSON.stringify({ name: "Ada", age: 36 });
console.log(text);        // {"name":"Ada","age":36}

JSON.parse only accepts a string. If you pass it an object that is already parsed, it coerces the object to the string "[object Object]" and throws. A surprising amount of “invalid JSON” confusion comes from double-parsing something that was already an object.

Always wrap JSON.parse in try/catch

If the input is not valid JSON, JSON.parse throws a SyntaxError. It does not return null or undefined, it throws, so any unguarded call can crash your program. In production code, wrap it.

function safeParse(text) {
  try {
    return JSON.parse(text);
  } catch (err) {
    console.error("Invalid JSON:", err.message);
    return null;
  }
}

The error message is usually specific, for example Unexpected token } in JSON at position 17, which points to where parsing failed. If you are debugging JSON by hand and the position is not enough, paste it into the JSON parser, which highlights the exact character that breaks it. The most common trigger is a trailing comma or an Unexpected token error, both of which are legal in JavaScript object literals but illegal in JSON.

Parsing a fetch response

The most common place you parse JSON is a network response. The fetch API gives you a .json() method that reads the body and runs JSON.parse on it, returning a promise.

async function getUser(id) {
  const res = await fetch(`/api/users/${id}`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();   // parses the body as JSON
}

Two things to watch. First, res.json() rejects if the body is not valid JSON, so wrap the await in try/catch just as you would a direct JSON.parse. Second, check res.ok before parsing: an error response is often an HTML error page, and trying to parse that as JSON is a frequent cause of Unexpected token < in JSON at position 0 (the < is the start of <!DOCTYPE html>).

The reviver function

JSON.parse takes an optional second argument, a reviver function, called for every key/value pair as the object is built. It lets you transform values during parsing, most often to turn date strings back into Date objects.

const text = '{"name":"Ada","born":"1815-12-10T00:00:00Z"}';

const data = JSON.parse(text, (key, value) => {
  if (key === "born") return new Date(value);
  return value;
});

console.log(data.born instanceof Date);  // true

JSON has no date type, so dates always travel as strings. A reviver is the clean way to rehydrate them without walking the object a second time afterward. Our guide on what JSON is covers which types JSON actually supports and which, like dates, you have to encode as strings.

How JSON maps to JavaScript types

Because JavaScript is where JSON came from, the type mapping is almost one to one. The only real caveat is numbers.

JSON JavaScript
object Object
array Array
string string
number number
true / false boolean
null null

The number caveat matters for large integers. JavaScript numbers are 64-bit floats, so an integer larger than Number.MAX_SAFE_INTEGER (about 9 quadrillion) loses precision when parsed. If your JSON carries big IDs, keep them as strings in the JSON, or use a library that parses them into BigInt.

Stringify options worth knowing

JSON.stringify has two optional arguments that solve common problems.

const data = { name: "Ada", password: "secret", roles: ["admin"] };

// Pretty-print with 2-space indent
JSON.stringify(data, null, 2);

// Whitelist only certain keys (drop password)
JSON.stringify(data, ["name", "roles"]);

The third argument sets indentation, which is the code equivalent of running output through an online JSON formatter. The second argument is a replacer: an array of keys to keep, or a function to transform values, handy for stripping secrets before logging. Leaving both off gives the compact single-line form you would get from a JSON minifier.

A few values do not survive stringify: undefined, functions, and symbols are dropped from objects (or become null in arrays), and BigInt throws. Plan for those rather than being surprised by missing keys.

Common parsing mistakes

Frequently asked questions

How do I parse JSON in JavaScript?
Call JSON.parse(text) where text is a JSON string. It returns a JavaScript object, array, or primitive. Wrap it in try/catch because it throws a SyntaxError on invalid input.

Why does JSON.parse throw “Unexpected token”?
The string is not valid JSON. Usual causes are single quotes instead of double quotes, unquoted keys, a trailing comma, or an HTML error page returned where JSON was expected. The JSON parser will show you the exact position.

Do I need to parse a fetch response manually?
No. Call await res.json() and it parses the body for you. Check res.ok first and wrap it in try/catch, since it rejects when the body is not valid JSON.

What is the reviver function in JSON.parse?
It is an optional second argument that runs for every key/value pair during parsing, letting you transform values, most commonly converting ISO date strings into Date objects.

Once your data is parsed, the rest of the toolkit helps you work with it: format or validate it in the JSON formatter, inspect large payloads in the JSON viewer, or browse all the free JSON tools. Doing the same job server-side? See how to parse JSON in Python.

Leave a Reply

Your email address will not be published. Required fields are marked *