Skip to content

Error Handling

Development

One of the advantages to working with a robust server-side framework is the built-in exception handling you get for free.

The challenge is, if you're making an XHR request (which Inertia does) and you hit a server-side error, you're typically left digging through the network tab in your browser's devtools to diagnose the problem.

Inertia solves this issue by showing all non-Inertia responses in a modal. This means you get the same beautiful error-reporting you're accustomed to, even though you've made that request over XHR.

Dialog element

Available since:@inertiajs/core:2.2.13

By default, Inertia < 3.x displays error modals using a custom <div> overlay. However, you can opt-in to using the native HTML <dialog> element instead, which provides built-in modal functionality including backdrop handling.

To enable this, configure the future.useDialogForErrorModal option in your application defaults.

js
createInertiaApp({
  // resolve, setup, etc.
  defaults: {
    future: {
      useDialogForErrorModal: true,
    },
  },
})

Production

In production you will want to return a proper Inertia error response instead of relying on the modal-driven error reporting that is present during development. To accomplish this, use the rescue_from method in your ApplicationController.

ruby
class ApplicationController < ActionController::Base
  rescue_from StandardError, with: :inertia_error_page

  private

  def inertia_error_page(exception)
    raise exception if Rails.env.local?

    status = ActionDispatch::ExceptionWrapper.new(nil, exception).status_code

    render inertia: 'ErrorPage', props: { status: }, status:
  end
end

Since rescue_from runs inside the controller, shared data defined via inertia_share is available automatically.

Error Page Example

You'll need to create the error page components referenced above. Here's an example you may use as a starting point.

vue
<script setup>
import { computed } from 'vue'

const props = defineProps({ status: Number })

const title = computed(() => {
  return {
    503: '503: Service Unavailable',
    500: '500: Server Error',
    404: '404: Page Not Found',
    403: '403: Forbidden',
  }[props.status]
})

const description = computed(() => {
  return {
    503: 'Sorry, we are doing some maintenance. Please check back soon.',
    500: 'Whoops, something went wrong on our servers.',
    404: 'Sorry, the page you are looking for could not be found.',
    403: 'Sorry, you are forbidden from accessing this page.',
  }[props.status]
})
</script>

<template>
  <div>
    <h1>{{ title }}</h1>
    <div>{{ description }}</div>
  </div>
</template>

Routing-level exceptions

Some exceptions (for example, routing 404s) occur before a controller is instantiated, so rescue_from won't catch them. Rails handles these via static files in public/ by default, which is fine for most apps.

If you want routing-level errors to render as Inertia pages too, point exceptions_app at your router and add error routes.

ruby
# config/application.rb
config.exceptions_app = routes
ruby
# config/routes.rb
match '/404', to: 'errors#show', defaults: { status: 404 }, via: :all
match '/422', to: 'errors#show', defaults: { status: 422 }, via: :all
match '/500', to: 'errors#show', defaults: { status: 500 }, via: :all
ruby
# app/controllers/errors_controller.rb
class ErrorsController < ApplicationController
  def show
    status = params[:status].to_i
    render inertia: 'ErrorPage', props: { status: }, status:
  end
end

Since this goes through the full Rails stack, shared data from inertia_share is available on error pages as well.