Skip to content
Topic 16 of 16
Theory

Errors and JSON

Why it matters

Programs break: the user typed letters instead of a number, the server sent corrupted data, a file is missing. Without handling, one such error stops the whole program. The try … catch construct lets you catch the error and decide what to do: show a message, use a default value, try again.

And JSON is the main data exchange format on the web: server responses come in it, settings are stored in it. Parsing "someone else's" JSON is the most common place where error handling is needed, which is why these topics are together.

What an error is

console.log("start");
const user = null;
console.log(user.name);   // TypeError — the program stops here
console.log("end");       // won't run

Output:

start
TypeError: Cannot read properties of null (reading 'name')

The most common kinds of errors:

Error When
SyntaxError the code breaks the rules (or the JSON is corrupted)
ReferenceError accessing a variable that doesn't exist
TypeError the action doesn't fit the type: calling a non-function, .name of null
RangeError a value out of the allowed range

try … catch

try {
  console.log("trying");
  const user = null;
  console.log(user.name);
  console.log("we won't get here");
} catch (error) {
  console.log("Caught:", error.name, "-", error.message);
}
console.log("the program keeps working");

Output:

trying
Caught: TypeError - Cannot read properties of null (reading 'name')
the program keeps working

The code in try runs as usual. If an error happens in it, execution jumps straight to catch, and the error object goes into the variable error. It has name (the kind) and message (the text). If there was no error, catch is skipped.

If you don't need the error object, you can omit the parentheses: catch { … }.

finally

The finally block runs always — whether there was an error or not. "Cleanup" goes there: close a file, hide a loading indicator.

try {
  console.log("loading...");
} catch (e) {
  console.log("error");
} finally {
  console.log("hide the spinner");
}

Output:

loading...
hide the spinner

throw — throwing your own error

Your own functions can also report a problem by "throwing" an error:

function buy(price, money) {
  if (price > money) {
    throw new Error("Not enough money");
  }
  return money - price;
}

try {
  console.log(buy(50, 100));
  console.log(buy(500, 100));
} catch (e) {
  console.log("Error:", e.message);
}

Output:

50
Error: Not enough money

throw stops the function like return, but instead of a result an error "flies" — up to the nearest catch higher in the call chain. You can throw a specific kind too: new TypeError(…), new RangeError(…).

Catching only your errors

Sometimes you need to handle one kind of error and let the others pass:

try {
  doSomething();
} catch (e) {
  if (e instanceof RangeError) {
    console.log("we'll fix it");
  } else {
    throw e;   // not ours — rethrow
  }
}

Catching "everything" and silently ignoring it is a bad habit: real bugs will hide.

JSON

JSON (JavaScript Object Notation) is a text format similar to JS objects:

{
  "name": "Anna",
  "age": 15,
  "skills": ["html", "css"],
  "admin": false,
  "pet": null
}

The rules are stricter than for JS objects: keys and strings only in double quotes, no comma after the last element, no comments, no functions and no undefined.

Object → JSON string: JSON.stringify

const user = { name: "Anna", age: 15, hobbies: ["drawing"] };
const text = JSON.stringify(user);
console.log(text);
console.log(typeof text);

Output:

{"name":"Anna","age":15,"hobbies":["drawing"]}
string

JSON.stringify(obj, null, 2) — pretty output with 2-space indentation.

JSON string → object: JSON.parse

const data = JSON.parse('{"title": "JS course", "lessons": 16}');
console.log(data.lessons + 1);

Output:

17

If the string isn't valid JSON, JSON.parse throws a SyntaxError:

try {
  JSON.parse("{name: 'Anna'}");   // a key without quotes, single quotes
} catch (e) {
  console.log(e.name);
}

Output:

SyntaxError

JSON.parse(JSON.stringify(obj)) is an old way to make a deep copy of a simple object.

How it works inside

When an error is thrown, the engine "unwinds" the call stack: it leaves the current function, then the one that called it, and so on, until it finds a try with a catch. If it doesn't, the program stops and the error is printed to the console. That's why catch can be placed not right around the dangerous line but where you know what to do with the error.

An error object also has a stack property — the list of functions the error "flew" through. It helps a lot in finding where things broke.

Common mistakes

  1. throw "text" instead of throw new Error("text"). A string has no name, message and stack. Always throw an error object.
  2. An empty catch. catch {} silently swallows any problems — bugs become impossible to find.
  3. try around asynchronous code. Such a try won't catch an error inside a setTimeout callback.
  4. Single quotes in JSON. JSON.parse("{'a': 1}") → SyntaxError. JSON uses only double quotes.
  5. Forgetting that stringify returns a string. JSON.stringify(obj).name is undefined.

Cheat sheet

What How
Catch an error try { … } catch (e) { … }
Always run finally { … }
Throw throw new Error("text")
A specific kind new TypeError(…), new RangeError(…)
Check the kind e instanceof RangeError
Text and kind e.message, e.name
Rethrow throw e;
To a JSON string JSON.stringify(obj)
From a JSON string JSON.parse(text)

Safe parsing

Easy+10 XP

Write a function safeParse(text): if text is valid JSON, return the parsed value, and if not — return null (the program must not crash).

safeParse('{"a": 1}')   → { a: 1 }
safeParse("[1, 2]")     → [1, 2]
safeParse("{oops}")     → null

Connect the connector to solve tasks

Task code runs on your own computer — faster and more reliable than in the browser. This needs the free CodeWithMe connector app. You only connect it once.

Looking for the connector on this computer…

  1. 1
    Download the connector for your system (Windows, macOS or Linux).Download the connectorOn the download page pick the file with your system in its name, e.g. windows-amd64.
  2. 2Run it and choose a folder for your solutions. It will install Python and Node.js there by itself when needed.
  3. 3
    Enter below the 6-digit code shown in the connector window (“Code for CodeWithMe”). If the browser asks about local network access — allow it.

The connector is open source (on GitHub), works only on your computer and runs code only after you enter the pairing code.