Skip to main content
Blaze follows the Express 4-argument error handler convention throughout. When any middleware or route handler throws an exception, or calls next(err) with a non-falsy value, the error skips all remaining normal handlers and flows to the nearest downstream error handler — a function with the signature (err, req, res, next). You can register one global error handler on the app, one per sub-router, or both.

BlazeError

BlazeError is Blaze’s built-in structured error class. Throw it anywhere in your handler stack to produce a deterministic HTTP error response with a status code, a message, and an optional meta bag that the error handler can spread into the JSON body.
Constructor signature:
number
required
The HTTP status code to send in the response (e.g. 400, 401, 403, 404, 422, 500).
string
required
A human-readable error message included in the response body.
Record<string, unknown>
Optional bag of additional fields spread into the JSON error response. Useful for machine-readable error codes, field-level validation errors, etc.
BlazeError extends Error and maintains a proper prototype chain, so err instanceof BlazeError works correctly in all environments — including after transpilation.

Global error handler

app.onError() registers a single global error boundary. Register it after all your routes and middleware so it catches errors from the entire app. The 4-argument signature — (err, req, res, next) — is what tells Blaze this is an error handler rather than a regular middleware.
Always register a global error handler in production. Without one, Blaze’s default behaviour is to return a plain { error: 'Internal Server Error' } with a 500 status — which leaks no details but also gives you no observability into what went wrong.

Route-level error boundaries

Sub-routers can register their own error handlers with router.onError(). These catch errors thrown within that router’s layer stack. You can handle specific error types locally and bubble the rest to the global handler by calling next(err).

Async error propagation

Blaze wraps every handler call so that rejected Promises are automatically forwarded to next(err). You do not need to write try/catch blocks in most handlers — Blaze catches uncaught async errors for you.
The only case where you need an explicit next(err) call is in synchronous middleware that conditionally forwards an error rather than throwing — for example, conditional auth logic that calls next(err) when validation fails and next() when it succeeds.

Error flow summary

1

Handler throws or calls next(err)

Any thrown error (sync or async) in a route or middleware is caught by Blaze’s layer wrapper and forwarded to the routing engine as next(err).
2

Normal layers are skipped

The router skips all remaining normal (req, res, next) handlers — they are not called while an error is in flight.
3

First matching error handler is called

The router finds the first Layer with a 4-argument function ((err, req, res, next)) downstream of where the error originated and invokes it.
4

Error handler calls next(err) to bubble

If the error handler can’t handle a particular error type, it calls next(err) again to pass the error to the next downstream error handler — typically the global one on app.
5

Global handler responds

app.onError() is the last stop. If it calls next(err) or throws, Blaze returns a bare 500 response.