Skip to content

Error Handling in TypeScript

Scattering error responses through every handler guarantees inconsistency. Instead, throw typed errors in your handlers and translate them to problem+json in one place.

flowchart LR
  H[Handler throws ApiError] --> M[Error middleware]
  M --> P[Map to problem+json]
  P --> R[Response with correct status]
Handlers throw; one place maps errors to responses

Define an error type that carries the status and problem fields, then a single handler that converts it. Anything unexpected becomes a 500 — and you never leak a stack trace to the client.

JavaScript
  • Consistency — every error leaves through the same shape.
  • Safety — unexpected errors become a generic 500; internals never leak.
  • Less code — handlers throw a line; they do not each build a response.
Advantages (Centralized Error Handling)Trade-offs
One consistent error shape across the API — no special casesSetting up the middleware is upfront work
Prevents internal errors from leaking to the clientA bug in the error middleware can break every error response
All logging happens in one place — easy to monitorRequires a well-designed error class hierarchy
Client-side retry logic behaves correctlyCustom error classes in TypeScript need care around transpilation

A try/catch in every controller Symptom:

  • Every route handler has its own try/catch
  • Error formats diverge — some routes send { error: "..." }, others { message: "..." }
  • Use one central error middleware instead: app.onError((err, c) => { ... })

Not logging the error before responding Symptom:

  • The error handler sends a response without logging
  • Production gets a 500 with nothing to debug it with
  • Log the error with request context (userId, path, method) before sending the response

💡 Real-world examples

Hono (the framework this course uses):

  • app.onError((err, c) => { ... }) — a global error handler
  • Handles every error type in one place

Express.js:

  • A 4-parameter error middleware: (err, req, res, next)
  • A centralized handler that logs to a monitoring system before responding is a common production pattern

Sources: Hono — error handling, Express.js error handling

What is the main benefit of a central error handler?
How should an unexpected (unanticipated) error be returned to the client?
In this pattern, how do handlers signal failure?