No matter how much your test your code, there might be an occassional exception raised during the execution of one of the routes in your code. You cannot wrap all the code in a huge try-except block, but you can use the built-in error-handling of Flask using the errrohandler hook that we have already seen when we wanted to have a unified look for 404 page not found.

Catching the Exception

@app.errorhandler(Exception)
def server_error(err):
    app.logger.exception(err)
    return "exception", 500

Alternativelly, using a template:

@app.errorhandler(Exception)
def server_error(err):
    return render_template('crash.html'), 500

Sample application handling the Exception

examples/flask/catch_exception/app.py

from flask import Flask
import datetime

app = Flask(__name__)

@app.errorhandler(Exception)
def server_error(err):
    app.logger.exception(err)
    return "exception", 500

@app.route("/")
def main():
    app.logger.info("main route")
    return "Hello " + str(datetime.datetime.now())

@app.route("/crash")
def crash():
    app.logger.info("crash route")
    a = 0
    b = 3 / a

Run as:

FLASK_APP=app FLASK_DEBUG=1 flask run

Output on the console for regular pages.

[2020-06-26 10:33:22,903] INFO in app: main route
127.0.0.1 - - [26/Jun/2020 10:33:22] "GET / HTTP/1.1" 200 -

Oputput of the crash

Visiting the http://localhost:5000/crash URL shows a stack trace like this on the command line:

[2020-06-26 10:33:29,633] INFO in app: crash route
[2020-06-26 10:33:29,633] ERROR in app: division by zero
Traceback (most recent call last):
  File ".../flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File ".../flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File ".../flask/catch_exception/app.py", line 20, in crash
    b = 3 / a
ZeroDivisionError: division by zero
127.0.0.1 - - [26/Jun/2020 10:33:29] "GET /crash HTTP/1.1" 200 -

The user only sees the word "exception".

Of course insted of returning that word, we could have used render_template to render any page. The status code returned by the page will be 500 as indicated by the second value returned.

Catching specific exceptions

In the above examples we use the catch-all Exception class, but you can be more specific about the exceptions and you can return different pages based on the error type. You could do this by checking the type of the err variable, but a probably cleaner way is to set up separate exception handler hooks for each exception type you'd like to deal with:

examples/flask/catch_specific_exception/app.py

from flask import Flask
import datetime

app = Flask(__name__)

@app.errorhandler(Exception)
def server_error(err):
    app.logger.exception(err)
    return "Some general exception", 500


@app.errorhandler(ZeroDivisionError)
def server_error(err):
    app.logger.exception(err)
    return "Cannot divide by 0", 500


@app.route("/")
def main():
    app.logger.info("main route")
    return "Hello " + str(datetime.datetime.now())

@app.route("/crash")
def crash():
    app.logger.info("crash route")
    raise Exception("just crash")

@app.route("/calc")
def calc():
    app.logger.info("calc route")
    a = 0
    b = 3 / a

Logging the Exception

In the above examples we keept using the app.logger.exception(err) expression to log the exception and the stack trace. If you are not interested in the stack-trace you can use the error logging method: app.logger.error(err).