When an error occurs, the
Lucky::ErrorHandler calls the auto-generated
Errors::Show action in
Errors::Show action has 3 key methods:
Errors::Show action will try to find a matching
render methods take the error as an argument and uses method
to find a match. If one matches, the error will be rendered.
For example, if
MyCustomError is raised, and there is a method for
handling it, that method will be used and
default_render will not be
def render(error : MyCustomError) error_html message: "Super Custom", status: 418 end
error_html is an automatically generated method on
shows an HTML page. You can customize it however you want. You can learn
more about how to customize how errors are displayed
later in the guide.
render method matches then the
default_render method will be
used. This method will send a
500 HTTP status code and either an HTML
page or a JSON response depending on the client’s desired format. If your
app is using API mode, it will only send JSON and not an HTML page.
You can learn more about how to customize how errors are displayed later in the guide.
This method handles reporting the error. We’ll talk about this more in the section on reporting errors
When using a browser with Lucky in development mode, Lucky uses the ExceptionPage shard to display a helpful page with your stack trace, and exception message.
When using JSON, Lucky will render errors as JSON whether in development or production.
Sometimes in development you want to see the page your users will see instead of the debug page.
To do so, change the the
settings.show_debug_output option to
# config/error_handler.cr Lucky::ErrorHandler.configure do |settings| settings.show_debug_output = false end
Remember to change it back once you’re done so you can see the debug page.
Let’s say you have an error class
MyCustomError in your app. When this
error is raised, you want to show a custom error to your users. Open up the
src/actions/errors/show.cr, and add your
method like this.
def render(error : MyCustomError) if html? error_html message: "Custom error message.", status: 418 else error_json message: "Custom error", status: 418 end end
If there is no
render for the exception, it will fallback to the
default one that is generated with every Lucky project:
default_render(error : Exception). You can customize that method in the same way by changing
the message or status codes:
def default_render(error : Exception) error_json "Something went very very wrong", status: 500 end
You can customize an error for just one format if you’d like:
def render(error : ThisIsOnlyImportantForJsonError) if json? error_json "Something for JSON clients", status: 418 end end
If the client wants JSON back, it will get this error message, otherwise
the method will return
nil and Lucky will fall back to using the
error_html methods in
These methods and the pages/serializers they call can be customized.
Errors::ShowPage. You can change that
page’s styles and content in
Lucky will also handle a few errors out of the box. For example,
Lucky::RouteNotFoundError will return a 404:
def render(error : Lucky::RouteNotFoundError) if html? error_html "Sorry, we couldn't find that page.", status: 404 else error_json "Not found", status: 404 end end
If you open
src/actions/errors/show.cr, you’ll see the other errors
that Lucky handles by default.
One of special note is the
Lucky::RenderableError. We’ll talk about
these more in the section on renderable
You may need to use custom errors for your control flow like manually rendering a 404 page when a user shouldn’t see certain pages, for example.
Since Lucky will pass all exceptions to the
Errors::Show action for you,
you can raise specific errors to display the error page you want.
get "/profiles/:slug" do profile = ProfileQuery.find_by_id_or_slug(slug) if current_user.is_allowed_to_view?(profile) # Return a 202 with the appropriate page html ShowPage, profile: profile else # raising this error will render the 404 page for you raise Lucky::RouteNotFoundError.new(context) end end
For rending non 200 status pages without raising errors, see rendering HTML with non 200 status
In general this should be a last resort or for libraries that want to provide default behavior for errors. Usually you should use
Errors::Showbecause it is more customizable and simpler to work with.
Lucky comes with a
Lucky::RenderableError module that can be included in
errors so that Lucky knows what the status code and message should be.
Lucky::RenderableError must have a
renderable_message method defined.
Lucky::RenderableErrors are handled with the
render(error : Lucky::RenderableError) method included in all new Lucky projects.
It looks something like this:
def render(error : Lucky::RenderableError) if html? error_html DEFAULT_MESSAGE, status: error.renderable_status else error_json error.renderable_message, status: error.renderable_status end end
If you want to make it so your error is rendered with this method, you can do this:
# Define your custom exception class NotAuthorizedError < Exception include Lucky::RenderableError def renderable_status 403 end def renderable_message "Not authorized" end end
NotAuthorizedError is raised, Lucky will use the defined status
code and message, unless you have a
render method for the error
render(error : NotAuthorizedError)).
src/actions/errors/show.cr file, there is a
By default this method is empty, but you can change it to report the
error however you want. You can send an email, send the error to one or
more services, or anything else you want.
# src/actions/errors/show.cr def report(error : Exception) Raven.capture(error) end
This will send the error report to Sentry. See the Raven README to learn more about installing and how to customize error reporting with Sentry.
You can use method overloading to report some errors differently than
others. For example, let’s say we have a
SuperScaryError that we want
to report by sending a text to the CEO. We can add a
report method that
handles that error:
def report(error : SuperScaryError) NotifyTheBoss.run! end
SuperScaryError will be handled by
report(error : SuperScaryError), and all other errors will be handled by the regular
report(error : Exception).
Some errors don’t need to be reported.
Errors::Show has a
macro that accepts an array of classes that should not be reported. By
default Lucky does not report
Lucky::RouteNotFoundError, but you can
add any errors there that you don’t want reported.
dont_report [ Lucky::RouteNotFoundError, MyCustomError ]