Skip to main content

Debugging & Error Handling

Flask provides a robust system for capturing exceptions, returning custom error responses, and providing detailed diagnostic information during development.

Registering Error Handlers

The primary way to handle errors is using the @app.errorhandler decorator. You can register handlers for specific HTTP status codes or for entire exception classes.

from flask import Flask, render_template
from werkzeug.exceptions import BadRequest

app = Flask(__name__)

# Handle 404 Not Found errors
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404

# Handle specific exception classes
@app.errorhandler(BadRequest)
def handle_bad_request(e):
return "Custom bad request message", 400

# Handle custom application exceptions
class DatabaseError(Exception):
pass

@app.errorhandler(DatabaseError)
def special_exception_handler(e):
return 'Database connection failed', 500

Handling Unhandled Exceptions (500 Errors)

When an exception occurs that doesn't have a specific handler, Flask catches it and returns a 500 Internal Server Error. If you register a handler for 500 or InternalServerError, Flask will pass an instance of InternalServerError to your function.

The original exception that triggered the error is available via the original_exception attribute, as seen in tests/test_user_error_handler.py:

from werkzeug.exceptions import InternalServerError

@app.errorhandler(500)
def handle_500(e):
# e is always an InternalServerError here
if e.original_exception is not None:
# Access the actual error (e.g., a KeyError or DatabaseError)
return f"Error: {type(e.original_exception).__name__}", 500
return "Internal Server Error", 500

Blueprint-Specific Handlers

Error handlers registered on a Blueprint only apply to requests handled by that blueprint. To register a handler on a blueprint that affects the entire application, use @bp.app_errorhandler.

from flask import Blueprint

auth_bp = Blueprint("auth", __name__)

# Only handles 403s raised within the 'auth' blueprint
@auth_bp.errorhandler(403)
def handle_auth_forbidden(e):
return "Auth access denied", 403

# Handles 401s for the entire application
@auth_bp.app_errorhandler(401)
def handle_global_unauthorized(e):
return "Please log in", 401

Debugging Utilities

Flask includes several helpers in src/flask/debughelpers.py to improve the developer experience by providing more descriptive error messages.

Template Loading Diagnostics

If you are having trouble finding templates, enable EXPLAIN_TEMPLATE_LOADING. Flask will log every attempt it makes to locate a template, including which loaders were used and which blueprints were checked.

app.config['EXPLAIN_TEMPLATE_LOADING'] = True

Form Data and Redirects

In debug mode, Flask raises a FormDataRoutingRedirect if a routing redirect (like adding a trailing slash) would cause a browser to drop POST data. This helps prevent silent data loss during development.

File Upload Errors

If you try to access request.files['key'] but the form was not submitted with enctype="multipart/form-data", Flask raises a DebugFilesKeyError with a detailed explanation of how to fix the form.

Logging

Flask uses a standard Python logger named after the application's import_name. You can access it via app.logger.

The logger is configured in src/flask/logging.py to:

  1. Set the level to DEBUG if app.debug is True.
  2. Log to wsgi.errors (the web server's error log) or sys.stderr.
@app.route('/debug-log')
def debug_log():
app.logger.debug("This only shows if app.debug is True")
app.logger.error("This will show in the WSGI error stream")
return "Logged"

Configuration Reference

KeyDefaultDescription
PROPAGATE_EXCEPTIONSNoneIf True, exceptions are re-raised instead of being handled by error handlers. Defaults to True in debug/testing.
TRAP_HTTP_EXCEPTIONSFalseIf True, HTTP exceptions are not handled and will propagate up the stack.
TRAP_BAD_REQUEST_ERRORSNoneIf True, KeyError exceptions from request data (like request.form) show the missing key in the response.
EXPLAIN_TEMPLATE_LOADINGFalseLogs detailed information about template lookup attempts.

Troubleshooting

  • Handlers not firing: Ensure the exception class you are handling is the one actually being raised. If you handle Exception, it will catch everything, including HTTPException subclasses.
  • Blueprint scope: Remember that @bp.errorhandler is local to the blueprint. If a 404 occurs because no route matched at all, it won't be caught by a blueprint handler; it must be caught by an @app.errorhandler(404).
  • Redirects: RequestRedirect (used for trailing slashes) is an internal routing exception and is not passed to error handlers. Flask handles these automatically to perform the redirect.