Handling Errors and Exceptions
When a view function raises an exception or a request results in an HTTP error, Flask can return a custom response instead of the default error page. You can register error handlers for specific HTTP status codes or for any exception class using the errorhandler decorator.
Registering Handlers for HTTP Status Codes
To provide a custom page for a specific HTTP error, such as a 404 Not Found, use the errorhandler decorator with the status code.
from flask import Flask, render_template
app = Flask(__name__)
@app.errorhandler(404)
def page_not_found(e):
# The exception object is passed to the handler
return render_template("404.html"), 404
The handler function receives the exception object (usually a werkzeug.exceptions.HTTPException) and must return a valid response, typically including the error's status code.
Handling Custom Exception Classes
You can also register handlers for arbitrary exception classes. This is useful for mapping internal application errors to specific HTTP responses.
class DatabaseError(Exception):
pass
@app.errorhandler(DatabaseError)
def special_exception_handler(e):
return "Database connection failed", 500
Flask uses the exception's Method Resolution Order (MRO) to find the most specific handler. If you have a handler for a parent class and a child class, the child's handler will be used for the child exception.
Blueprint-Specific Error Handlers
Error handlers registered on a Blueprint using the errorhandler decorator only trigger for requests handled by that specific blueprint.
from flask import Blueprint, abort
bp = Blueprint("api", __name__)
@bp.errorhandler(403)
def handle_forbidden(e):
return {"error": "Forbidden access to API"}, 403
@bp.route("/secret")
def secret():
abort(403)
If you want a blueprint to register a handler that applies to the entire application, use the app_errorhandler decorator instead.
Handling Unhandled Exceptions (500 Errors)
When an exception occurs that has no specific handler, Flask raises an InternalServerError (HTTP 500). You can register a handler for 500 errors to provide a consistent "crash" page. In this case, the original exception that caused the failure is available via the original_exception attribute.
from werkzeug.exceptions import InternalServerError
@app.errorhandler(500)
def handle_500(e):
# e is an instance of InternalServerError
if e.original_exception is not None:
# You can log or inspect the root cause here
app.logger.error(f"Original error: {e.original_exception}")
return f"Internal error: {type(e.original_exception).__name__}", 500
return "A direct 500 error occurred", 500
Catch-all Exception Handlers
You can register a handler for the base Exception class or HTTPException to catch all errors of that type.
from werkzeug.exceptions import HTTPException
@app.errorhandler(HTTPException)
def handle_http_exception(e):
"""Return JSON instead of HTML for HTTP errors."""
# start with the correct headers and status code from the error
response = e.get_response()
# replace the body with JSON
response.data = flask.json.dumps({
"code": e.code,
"name": e.name,
"description": e.description,
})
response.content_type = "application/json"
return response
@app.errorhandler(Exception)
def handle_exception(e):
# Pass through HTTP errors
if isinstance(e, HTTPException):
return e
# Now you're handling non-HTTP exceptions only
return render_template("500_generic.html"), 500
Configuration and Troubleshooting
Exception Propagation
By default, Flask handles exceptions and returns an error response. However, in debug or testing modes, you might want exceptions to propagate up to the server or test runner.
PROPAGATE_EXCEPTIONS: If set toTrue, exceptions are re-raised instead of being handled. This is automaticallyTruewhenDEBUGorTESTINGis enabled.
Bad Request Errors
When accessing a missing key in request.form or request.args, a BadRequestKeyError is raised.
TRAP_BAD_REQUEST_ERRORS: WhenTrue, these errors will show the specific missing key in the error message during debug mode, rather than a generic 400 Bad Request.
Registration Requirements
- Handlers must be registered for classes, not instances.
@app.errorhandler(ValueError)is correct;@app.errorhandler(ValueError())will raise aTypeError. - Routing exceptions like
RequestRedirect(used for slash redirects) are handled internally by Flask and are not passed to custom error handlers. - If an error handler itself raises an exception, Flask will log it and return a default 500 response to prevent infinite loops.