Flask Error Handling

Flask provides a flexible error handling mechanism that can catch and handle various errors in the application.

Good error handling is not just about "no bugs" — it is about giving users a friendly experience when bugs do occur.

This chapter introduces how to customize error pages and manage logs in Flask.


Custom error page

By default, Flask displays a simple black-background, white-text page for errors such as 404.

Usage@app.errorhandlerDecorators can be used to customize error pages for specific HTTP status codes:

Example

from flask import Flask, render_template

app = Flask(__name__)

# Handle 404 error - page not found
@app.errorhandler(404)
def page_not_found(error):
    # Note: must explicitly return status code 404
    return render_template("404.html"), 404

# Handle 500 error - internal server error
@app.errorhandler(500)
def internal_error(error):
    return render_template("500.html"), 500

# Handle 403 error - access forbidden
@app.errorhandler(403)
def forbidden(error):
    return render_template("403.html"), 403

The corresponding 404 template:

Example

<!-- File path: templates/404.html -->
<!DOCTYPE html>
<html>
<head>
    <title>404 - Page Not Found</title>
    <style>
        body { text-align: center; padding-top: 60px; font-family: Arial; }
        h1 { font-size: 72px; color: #e74c3c; margin: 0; }
        p { color: #666; font-size: 18px; }
        a { color: #3498db; }
    </style>
</head>
<body>
    <h1>404</h1>
    <p>Sorry, the page you visited does not exist.</p>
    <p><a href="/">Back to Home</a></p>
</body>
</html>

InerrorhandlerIn the decorated function,returnYou must explicitly specify the status code. If you don't write it, 404, Flask will return a 200 status code by default, and browsers and search engines won't treat it as an error page.


Exception class registration

Besides the status code,@app.errorhandlerYou can also directly register exception classes:

Example

from werkzeug.exceptions import HTTPException

@app.errorhandler(HTTPException)
def handle_http_exception(error):
    """Handle all HTTP exceptions uniformly (e.g., 400, 401, 403, 404, etc.)"""
    return f"""
<h1>HTTP Error {error.code}</h1>
    <p>{error.description}</p>
<p><a href="/">Back to EXAMPLE homepage</a></p>
    """
, error.code

Using abort to trigger errors

In your view function, useabort()to actively trigger an HTTP error:

Example

from flask import abort

# Simulate an article database
articles = {
    1: {"title": Flask Tutorial},
    2: {"title": "Python Basics"},
}

@app.get("/article/<int:article_id>")
def view_article(article_id):
    article = articles.get(article_id)

    if article is None:
        # Article does not exist, return 404
        # The description parameter will be passed to errorhandler
        abort(404, description=f"Article ID {article_id} does not exist")

    return f"<h1>{article['title']}</h1>"

@app.get("/admin")
def admin_panel():
    # User without admin permissions accesses the admin backend
    abort(403, description="You do not have admin permissions")

Logging

Flask uses the Python standard library'sloggingModule, throughapp.loggerThen you can log the record.

Logging is crucial for troubleshooting — don't just useprint(), as logs provide richer context and better control.

Example

from flask import Flask, request

app = Flask(__name__)

@app.route("/")
def index():
    # Different log levels
    app.logger.debug("Access homepage")                    # Debug information, usually not output in production
    app.logger.info("User from IP: %s", request.remote_addr)  # General information
    app.logger.warning("Abnormal access pattern detected")         # Warning: needs attention but does not affect operation
    app.logger.error("Database connection failed")               # Error: functionality is affected
    app.logger.critical("Insufficient disk space, service is about to stop")  # Critical error: service may stop
    return "OK"

Log levels (from low to high):

Level Use Case
DEBUG Detailed information during development debugging is not output in the production environment by default.
INFO General runtime information, such as request logs and service startup
WARNING Warning messages, potential issues that don't affect current operation
ERROR Error messages, a feature failed but the service is still running
CRITICAL Critical errors, may cause the service to stop

In Debug mode, Flask's log level is automatically set toDEBUG. In production environments, set it as needed toINFOorWARNING, to avoid outputting too much useless information.


Configure log output

Write logs to a file for easier post-hoc analysis and troubleshooting:

Example

import logging
from logging.handlers import RotatingFileHandler

# Configure file log handler: rotate after the log file reaches 10MB
handler = RotatingFileHandler(
    "example_app.log",     # Log file path
    maxBytes=10 * 1024 * 1024,  # Maximum single file size 10MB
    backupCount=5          # Keep the last 5 backups
)

# Set log format
handler.setFormatter(logging.Formatter(
    "[%(asctime)s] %(levelname)s in %(module)s: %(message)s"
))

# Add handler to Flask's logger
app.logger.addHandler(handler)
app.logger.setLevel(logging.INFO)

Catching unhandled exceptions

Usageapp.errorhandler(500)You can catch unhandled exceptions and record them in logs:

Example

import traceback

@app.errorhandler(500)
def internal_error(error):
    # Log the full exception stack trace
    app.logger.error("Internal server error:\n%s", traceback.format_exc())

    # Show a friendly error page to the user
    return """
<h1>500 - Internal Server Error</h1>
<p>Sorry, the server encountered an unexpected error. We have recorded the problem. Please try again later.</p>
<p>If the problem persists, please contact EXAMPLE technical support.</p>
    """
, 500

Quick reference for common HTTP error codes

Status Code Meaning Common Causes
400 Bad Request Malformed request parameters, missing required fields
401 Unauthorized User not logged in or authentication failed
403 Forbidden User is logged in but has no access permission
404 Not Found Resource (article, user, etc.) does not exist
405 Method Not Allowed Using the wrong HTTP method (e.g., using GET to access a POST endpoint)
500 Internal Server Error Unhandled errors such as code exceptions and database connection failures
other extensions