11 minutes read

Applications fail; servers occasionally do it, too. Sooner or later, you will have to face exceptions. Even if your code is 100% correct, you will encounter them from time to time. What causes them? For example, a client aborted a request while the application was still processing the incoming data. Or there's a programming error in the library you use. Or a database server is overloaded and cannot handle the request. Or a file system is full. Or the network connection fails, and so on. This is just a minuscule portion of the problems you may encounter.

By default, if your application runs in the production mode and there's an error, Flask will display a plain page and log an exception. You can improve it, though. In this topic, we'll look at how to do it.

Common error codes

As programmers, we should understand the main error types:

  • 404 Not found

The well-known "You made a mistake with that URL, mate" message. It is a very common mistake on the Internet. The standard HTTP response 404 code indicates that the client was able to communicate with the server, but the server cannot find the data as per request.

  • 403 Forbidden

403 Forbidden means that you have limited or no access to the content on the page you are trying to reach.

  • HTTP Error Code 410

Do you know that 404 Not Found has a sibling 410 Gone? It indicates that the target resource is no longer available on the original server, and this state is likely to be permanent. When you don't know whether this state is temporary or permanent, use the 404 status code instead.

  • Internal server error 500

It usually occurs due to programming errors or when the server is overloaded. It may be a good idea to have a placeholder page for this because your app will crash sooner or later.

Error handlers

Once you are familiar with the main error types, it's time to learn how to catch and direct these errors to the appropriate pages. The error handler is a function that returns a response when an error type occurs. It is quite similar to how a view function returns a response when it matches a request URL. To register an error handler, we need to pass an instance of the error to a built-in errorhandler decorator or a register_error_handler method. You can set a handler to catch any exception, but if you work with Flask, most likely, you'll deal with an instance of werkzeug.exceptions.HttpException, a base class for all HTTP exceptions.

Below is an example of processing the 404 not found exception. Remember that the render_template function renders a template from the template folder with the specified context:

from flask import render_template

@app.errorhandler(404)
def page_not_found(e):  # error instance is automatically passed to the function
    return render_template('404.html'), 404  # set the 404 status explicitly

Here, the error handler is in the errorhandler decorator. Note that when you register a handler for a werkzeug.exceptions.HTTPException subclass like NotFound, you can pass their HTTP code (NotFound.code == 404) to the decorator as an argument. The decorator automatically passes the error instance to the function. Another important thing is that the status code will not be directed to the handler's response automatically. Make sure that you provide the appropriate HTTP status code on returning a response from the handler.

Once you have this method, any 404 exception raised during execution will render the 404.html template.

Here's an example of how Google handles a 404 error:

404.html template

Sometimes, you'll also need to return the response as JSON. To do so, you can use jsonify(), and errorhandler will promote it as a JSON error message:

from flask import jsonify

@app.errorhandler(404)
def page_not_found(e):
    return jsonify(error=str(e)), 404

Exception class

Python provides us with several built-in exceptions that force a program to output an error if something goes wrong. However, you may need to introduce a new custom exception to give more context for the error.

Let's see how you can create a simple exception when something goes wrong with memory usage:

class InsufficientStorage(werkzeug.exceptions.HTTPException):
    code = 507
    description = 'Not enough storage space.'

app.register_error_handler(InsufficientStorage, handle_507)

Register_error_handler() is an alternative way to register an error handler. Similar to the errorhandler decorator, it must know the error to handle and what function it should invoke when this error is raised. We can provide them as arguments.

In the example above, we have registered the handler and invoked the handle_insuficcient method. It should be predefined, just like the page_not_found function in the Error handlers paragraph.

Now, if something raises InsufficientStorageError, Flask will know exactly what to do.

The abort() function

Flask also comes with a handy abort() function that terminates a request with an HTTP error code. If you want to quickly give an error a custom response, use the abort() function for this. It will also provide you with a simple black-and-white error page with a basic description but no frills about it.

The abort helper wraps errors into a HTTPException so they can behave properly. You can try the following:

from flask import abort
abort(400)

It will produce a 400 HTTP code and the following output:

{
    "message": "The browser sent a request that this server could not understand."
}

You can edit this message:

from flask import abort
abort(400, 'My custom message')

The output will look like this:

{
    "message": "My custom message"
}

The abort() method is beneficial if you don't want to spend a lot of time processing errors in the code. Flask doesn't automatically return a proper template or a JSON message to the client, and sometimes you don't want to create anything fancy. That's when you use abort() that handles errors (no exception raising, though) for you.

Conclusions

In this topic, you've found out the main HTTP error types and learned to intercept and direct these errors to the appropriate pages using the errorhandler decorator and register_error_handler function. You've also learned how to create custom errors to provide more context or, on the contrary, use the abort() function to return simple messages. Keep up the good work!

23 learners liked this piece of theory. 1 didn't like it. What about you?
Report a typo