Masonite Documentation
v4.0
v4.0
  • Introduction and Installation
  • Prologue
    • Creating A Blog Tutorial
    • Release Cycle
    • Contributing Guide
    • How To Contribute
  • The Basics
    • Routing
    • Controllers
    • Middleware
    • Response
    • Request
    • Static Files
    • Views
    • Environments
    • Configuration
    • Error Handling
  • Features
    • API Development
    • Authentication
    • Authorization
    • Broadcasting
    • Caching
    • Compiling Assets
    • Commands
    • CSRF Protection
    • Events
    • Facades
    • Filesystem and Uploading
    • Hash ID's
    • Helpers
    • Mail
    • Notifications
    • Package Development
    • Queues and Jobs
    • Rate Limiting
    • Sessions
    • Task Scheduling
    • Tinker Shell (REPL)
    • Validation
  • Architecture
    • Service Providers
    • Service Container
  • Security
    • CORS
    • Hashing
  • Masonite ORM
    • To Masonite ORM Docs
  • Testing
    • Getting Started
    • HTTP Tests
    • Database Tests
    • Commands Tests
    • Console Tests
    • Mocking
    • Extending
  • Official Packages
    • Masonite Debugbar
  • How-to Guides
    • Handling AJAX requests with expired authentication
    • Build Email Verification from Scratch With Masonite Framework and JSON Web Tokens
    • Deploying a Masonite Application to Heroku
    • How To Deploy Masonite to PythonAnywhere
    • How-To: Use RabbitMQ with Masonite 2.0 queues
    • How To Use The Repository Pattern with Masonite
    • Making Masonite and Laravel Mix work together
  • What's New
    • Masonite 1.3
    • Masonite 1.4
    • Masonite 1.5
    • Masonite 1.6
    • Masonite 2.0
    • Masonite 2.1
    • Masonite 2.2
    • Masonite 2.3
    • Masonite 3.0
  • Upgrade Guide
    • Masonite 1.3 to 1.4
    • Masonite 1.4 to 1.5
    • Masonite 1.5 to 1.6
    • Masonite 1.6 to 2.0
    • Masonite 2.0 to 2.1
    • Masonite 2.1 to 2.2
    • Masonite 2.2 to 2.3
    • Masonite 2.3 to 3.0
    • Masonite 3.0 to 4.0
Powered by GitBook
On this page
  • Global Exception Handler
  • Debug Mode
  • Lifecycle
  • Report Exceptions
  • Simple Exceptions
  • HTTP Exceptions
  • Renderable Exceptions
  • Existing Exception Handlers
  • Adding New Handlers
  • Catch All Exceptions
Edit on GitHub
Export as PDF
  1. The Basics

Error Handling

PreviousConfigurationNextAPI Development

Last updated 2 years ago

Masonite error handling is based on the ExceptionHandler class which is responsible for handling all exceptions thrown by your application.

Global Exception Handler

All exceptions are handled by the ExceptionHandler class which is bound to the through exception_handler key.

This handler has a logic to decide how to handle exceptions depending on the exception type, the environment type, the request accepted content type and the .

This handler has by default one driver which is responsible of handling errors in development by providing a lot of context to help debug your application.

Debug Mode

When is enabled all exceptions are rendered through Exceptionite HTML debug page.

When disabled, the default errors/500.html, errors/404.html, errors/403.html error pages are rendered depending on error type.

Never deploy an application in production with debug mode enabled ! This could lead to expose some sensitive configuration data and environment variables to the end user.

Lifecycle

When an exception is raised it will be caught by the ExceptionHandler. Then the following cycle will happen:

In Development

  1. A masonite.exception.SomeException event will be fired.

  2. A specific ExceptionHandler will be used if it exists for the given exception.

  3. Exceptionite will then handle the error by rendering it in the console

    • and with the Exceptionite JSON response if accepted content is application/json

    • else with the Exceptionite HTML error page

In Production

  1. A masonite.exception.SomeException event will be fired.

  2. A specific ExceptionHandler will be used if it exists for the given exception. In this case the default ExceptionHandler won't process the exception anymore.

  3. Else this exception has not been yet handled and will be handled as an HTTP exception with 500 Server Error status code.

Report Exceptions

To report an exception you should simply raise it as any Python exceptions:

def index(self, view:View):
    user = User.find(request.param("id"))
    if not user:
        raise RouteNotFoundException("User not found")

There are different type of exceptions.

Simple Exceptions

HTTP Exceptions

HTTP exceptions are standard exceptions using frequently used HTTP status codes such as 500, 404 or 403.

Those exceptions will be rendered by the HTTPExceptionHandler with the corresponding status code and the corresponding default error template if it exists in errors/. (Note that in debug mode this template won't be rendered and the default Exceptionite error page will be rendered instead).

The following HTTP exceptions are bundled into Masonite:

  • AuthorizationException (403)

  • RouteNotFoundException (404)

  • ModelNotFoundException (404)

  • MethodNotAllowedException (405)

In a default Masonite project, existing errors views are errors/404.html, errors/403.html and errors/500.html. Those views can be customized.

You can also build a custom HTTP exception by setting is_http_exception=True to it and by defining the get_response(), get_status() and get_headers() methods:

class ExpiredToken(Exception):
    is_http_exception = True

    def __init__(self, token):
        super().__init__()
        self.expired_at = token.expired_at

    def get_response(self):
        return "Expired API Token"

    def get_status(self):
        return 401

    def get_headers(self):
        return {
            "X-Expired-At": self.expired_at
        }

When the above exception is raised, Masonite will look for the error view errors/401.html in the default project views folder and will render it with a 401 status code. The content of get_response() method will be passed as the message context variable to the view.

If this view does not exist the HTML response will be directly the content of the get_response() method with a 401 status code.

Renderable Exceptions

If you want more flexibility to render your exception without using the HTTPExceptionHandler above, you can just add a get_response() method to it. This method will be given as first argument of response.view(), so that you can render simple string or your own view template.

class CustomException(Exception):

    def __init__(self, message=""):
        super().__init__(message)
        self.message = message

    def get_response(self):
        return self.message

Here when raising this exception in your code, Masonite will know that it should render it by calling the get_response() method and here it will render as a string containing the message raised.

Note that you can also set an HTTP status code by adding - as for HTTP exceptions - the get_status() method to the exception.

class CustomException(Exception):

    def __init__(self, message=""):
        super().__init__(message)
        self.message = message

    def get_response(self):
        return self.message

    def get_status(self):
        return 401

Existing Exception Handlers

Existing Exception Handlers are:

  • HTTPExceptionHandler

  • DumpExceptionHandler

You can build your own Exception Handlers to override the way Masonite handles an exception that is thrown or to add new behaviours.

Adding New Handlers

A handler is a simple class with a handle() method that Masonite will call when a specific exception is thrown by the application.

As an example, you could handle specifically ZeroDivisionError exceptions that could be thrown by your application. It will look like this:

class DivideException:

    def __init__(self, application)
        self.application = application

    def handle(self, exception):
        self.application.make('response').view({
            "error": str(exception),
            "message": "You cannot divide by zero"
        }, status=500)

The name of the class can be whatever you like. In the handle method you should manually return a response by using the response class.

You will then need to register the class to the container using a specific key binding. The key binding will be {exception_name}Handler. You can do this in your Kernel file.

To register a custom exception handler for our ZeroDivisionError we would create a binding that looks like this:

from app.exceptions.DivideException import DivideException

self.application.bind(
    "ZeroDivisionErrorHandler",
    DivideException(self.application)
)

You can add this binding in your AppProvider or in Kernel.py.

Now when your application throws a ZeroDivisionError, Masonite will use your handler rather than Masonite's own exception handlers.

Catch All Exceptions

If you want to hook up an error tracking service such as Sentry or Rollbar you can do this through event listeners: each time an exception is raised, a masonite.exception.{TheExceptionType} is fired, allowing to run any custom logic.

class SentryListener:

    def handle(self, exception_type: str, exception: Exception):
        # process the exception with Sentry
        # ...
class AppProvider(Provider):

    def register(self):
        self.application.make("event").listen("masonite.exception.*", [SentryListener])

If exception is an it will be handled by the HTTPExceptionHandler which is responsible for selecting an error template (errors/500.html, errors/404.html, errors/403.html) and rendering it.

If exception is a it will be rendered accordingly.

Simple exceptions will be handled as a 500 Server Error if no are defined for it.

First to run your custom logic:

In a you then need to register this listener:

Service Provider
HTTP exception
Renderable exception
custom exceptions handlers
Service Container
Exceptionite
configured exception handlers
Debug mode
create a listener