Error Handing

Built-In Errors

Blitz comes with a number of useful errors you can use throughout your application.

  • AuthenticationError
    • name: "AuthenticationError"
    • statusCode: 401
    • Default message: "You must be logged in to access this"
  • CSRFTokenMismatchError
    • name: "CSRFTokenMismatchError"
    • statusCode: 401
    • Default message: "You must be logged in to access this"
  • AuthorizationError
    • name: "AuthorizationError"
    • statusCode: 403
    • Default message: "You are not authorized to access this"
  • NotFoundError
    • name: "NotFoundError"
    • statusCode: 404
    • Default message: "This could not be found"

To use, import from

blitz and use like any JavaScript Error. If you're curious, you can see the source code for these.

import {AuthenticationError} from "blitz"
try {
throw new AuthenticationError()
} catch (error) {
if ( === "AuthenticationError") {
// Handle this error appropriately, like show a login screen

You can throw these or any other errors from anywhere in your app, whether on the server or on the client.

Catching and Handling Errors on the Client

By default, new Blitz applications come with

react-error-boundary installed with a top-level ErrorBoundary and FallbackComponent in app/pages/_app.tsx.

It looks something like this:

// app/pages/_app.tsx
import {AppProps, ErrorComponent} from "blitz"
import {ErrorBoundary} from "react-error-boundary"
import {queryCache} from "react-query"
import LoginForm from "app/auth/components/LoginForm"
export default function App({Component, pageProps}: AppProps) {
return (
onReset={() => {
// This ensures the Blitz useQuery hooks will automatically refetch
// data any time you reset the error boundary
<Component {...pageProps} />
function RootErrorFallback({error, resetErrorBoundary}) {
if ( === "AuthenticationError") {
return <LoginForm onSuccess={resetErrorBoundary} />
} else if ( === "AuthorizationError") {
return (
title="Sorry, you are not authorized to access this"
} else {
return (
<ErrorComponent statusCode={error.statusCode || 400} title={error.message ||} />

That means all errors will at least be caught at the root level. However, you can also add

<ErrorBoundary> anywhere else in your app for more localized error handiling. If an error is caught by an <ErrorBoundary> somewhere down inside your app tree, then it will not reach the root ErrorBoundary unless you re-throw it.

Handling Server Errors on the Client

A really awesome feature of Blitz is that you can throw any error from a Blitz query or mutation and then use an ErrorBoundary on the frontend to catch and handle it.

For example, with the above

_app.tsx, you can throw AuthenticationError inside a Blitz query and then a login screen will automatically show in the client because that root ErrorBoundary is rendering <LoginForm> if === 'AuthenticationError'.

Custom Errors

For errors other than what Blitz provides, it's recommended to create custom Error classes. You can then add custom data attributes that help you handle the error.

Here's an example of how to create a custom error. It's a JavaScript class, so you can be as creative as you want.

export class UsernameTakenError extends Error {
name = "UsernameTakenError"
constructor({suggestedUserName}) {
this.suggestedUserName = suggestedUserName
throw new UsernameTakenError({suggestedUserName: "second_best"})

Then on the client, you can use a

FallbackComponent like above, or you can handle the error in your form submit handler like this.

onSubmit={async (values) => {
try {
await setUsername(values.username)
} catch (error) {
if ( === "UsernameTakenError") {

Error Pages

See the

Error Pages documentation to learn about custom 404 and 500 error pages.

Idea for improving this page?Edit it on GitHub
Bytes Newsletter