Zen Router

Error handling

Aborting from handlers, and customizing error responses.

Aborting from handlers

Use abort() to short-circuit a handler and return an error response:

import { abort } from "@liveblocks/zenrouter";

zen.route(
  "GET /api/posts/<postId>",

  async ({ p }) => {
    const post = await db.getPostById(p.postId);
    if (!post) {
      abort(404);
    }
    return { id: post.id, title: post.title };
  }
);

abort() throws internally and never returns. By default, it produces a JSON response like { "error": "Not Found" } using the standard message for the status code. You can customize the error shape with the router’s error handler (see below).

Default error shape

By default, all error responses are JSON with at least an error key:

{ "error": "Not Found" }

For validation errors (422), a reason field is included with details:

{
  "error": "Unprocessable Entity",
  "reason": "Value at key 'title': expected string"
}

Custom error handling

Use onError to customize the error response shape for all HTTP errors. For example, when abort(404) is called, .onError() will get called with an error object containing { status: 404, message: "Not Found" }:

zen.onError((error, { req, ctx }) => {
  // error.status  — the HTTP status code
  // error.message — the error message
  return json(
    {
      code: error.status,
      message: error.message,
      path: new URL(req.url).pathname,
    },
    error.status
  );
});

Use onUncaughtError to handle unexpected errors (bugs, unhandled exceptions):

zen.onUncaughtError((error, { req, ctx }) => {
  console.error("Uncaught error:", error);
  return json({ error: "Something went wrong" }, 500);
});

Both handlers can only be registered once per router.

Shared error handler

If you use ZenRelay with multiple routers, you can share an ErrorHandler instance across them:

import { ErrorHandler, ZenRouter, ZenRelay } from "@liveblocks/zenrouter";

const errorHandler = new ErrorHandler();
errorHandler.onError((error) => {
  return json({ code: error.status, message: error.message }, error.status);
});

const api = new ZenRouter({ authorize: myAuth, errorHandler });
const admin = new ZenRouter({ authorize: adminAuth, errorHandler });
const app = new ZenRelay({ errorHandler });

Built-in error responses

In addition to any abort() calls you make manually, Zen Router automatically aborts under these conditions:

StatusWhen
400 Bad RequestPath params are malformed or fail validation
403 Forbiddenauthorize returns a falsy value
404 Not FoundNo route matches the URL
405 Method Not AllowedURL matches but HTTP method doesn’t
422 Unprocessable EntityRequest body fails schema validation
500 Internal Server ErrorUncaught error in a handler

See also the Request lifecycle.

On this page

Made withHeartby Liveblocks