Stop 04 · JavaScript & TypeScript for BackendTopics · 3/12

Error Handling

Part of the Backend Developer Roadmap

In short

In the browser an uncaught error breaks one tab. On a server it can crash the whole process for every user. Handling errors well is what makes a backend trustworthy.

Designing how your backend surfaces failures — custom error classes, centralized error middleware, and consistent error response shapes for API consumers.

The mascot crouches behind the stumps as a wicketkeeper, catching a cricket ball.

Think of it like this

The wicketkeeper's gloves

When the batter misses, the ball doesn't fly to the boundary. The wicketkeeper catches it and the game goes on. try/catch is your wicketkeeper: when something fails, you catch it, deal with it, and the server keeps running.

Watch it happen

Where an error travels

DB call
throw
catch
Log
Response

1/5Your service calls db.findUser(42). The database is down, so the Promise rejects.

The big ideas

What you need to know

try/catch works with await

Wrap awaited calls in try/catch. A rejected Promise becomes a normal thrown error you can catch.

Throw real Error objects

throw new Error("...") keeps a stack trace. Throwing a plain string loses where it came from.

Custom error classes

class NotFoundError extends Error lets you check instanceof and map each type to the right HTTP status.

Keep the cause

new Error("Payment failed", { cause: err }) wraps a low-level error without losing the original.

See it in code

Walk through the code

ts
1class NotFoundError extends Error {2  constructor(what: string) {3    super(`${what} not found`);4    this.name = "NotFoundError";5  }6}7async function getOrder(id: string) {8  try {9    const order = await db.orders.findById(id);10    if (!order) throw new NotFoundError(`Order ${id}`);11    return order;12  } catch (err) {13    if (err instanceof NotFoundError) throw err;14    throw new Error("Could not load order", { cause: err });15  }16}

1/4A custom error class with its own name, so callers can recognise it.

Expected problems, like a missing order, get their own error type. Unexpected ones get wrapped with cause so the logs show the real reason.

Save yourself the pain

Common mistakes

Oops

An empty catch {} that silently swallows the error.

Do this instead

At least log it. A silent catch turns a clear crash into a mystery bug that takes days to find.

Oops

Sending err.stack or raw database errors to the client.

Do this instead

Log details on the server. Send users a short message and a status code, never your internals.

Your mission

Build an error ladder

~25 min

Quick check

Why is throw new Error("Not found") better than throw "Not found"?

Go deeper

  1. 1Create a custom `AppError` class carrying a status code and message.
  2. 2Build a centralized Express error-handling middleware that catches all thrown errors.
  3. 3Design a consistent JSON error response shape used across your entire API.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge