Flask Cheatsheet
Error Handling
Use this Flask reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
HTTP Error Handlers
from flask import render_template, jsonify @app.errorhandler(404) def not_found(e): return render_template("errors/404.html"), 404 @app.errorhandler(403) def forbidden(e): return render_template("errors/403.html"), 403 @app.errorhandler(500) def internal_error(e): return render_template("errors/500.html"), 500
The error object e is a werkzeug.exceptions.HTTPException with:
e.code # 404 e.name # "Not Found" e.description # default description string
abort() — Raise HTTP Errors
from flask import abort abort(400) # Bad Request abort(401) # Unauthorized abort(403) # Forbidden abort(404) # Not Found abort(405) # Method Not Allowed abort(409) # Conflict abort(410) # Gone abort(422) # Unprocessable Entity abort(429) # Too Many Requests abort(500) # Internal Server Error abort(404, "Post not found") # custom description abort(Response("custom body", 418)) # abort with a full Response object
abort() raises an exception immediately — code after it does not run.
Catching All HTTP Exceptions
from werkzeug.exceptions import HTTPException @app.errorhandler(HTTPException) def http_exception(e): return jsonify({ "error": e.name, "description": e.description, "status": e.code, }), e.code
This handler runs for all HTTP errors not caught by a more specific handler.
Catching Any Exception
@app.errorhandler(Exception) def unhandled_exception(e): app.logger.exception("Unhandled exception") return render_template("errors/500.html"), 500
In debug mode, Flask shows the interactive debugger instead of calling exception handlers. Handlers only run in production (
DEBUG=False).
Blueprint-Level Error Handlers
Blueprint handlers only fire for errors raised within that blueprint (Flask 2.3+):
@api_bp.errorhandler(404) def api_not_found(e): return jsonify({"error": "Not Found"}), 404 @api_bp.errorhandler(Exception) def api_error(e): return jsonify({"error": str(e)}), 500
Use app_errorhandler on a blueprint to register an app-wide handler:
@api_bp.app_errorhandler(404) def global_not_found(e): return jsonify({"error": "Not Found"}), 404
Custom Exception Classes
class AppError(Exception): status_code = 400 def __init__(self, message, status_code=None, payload=None): super().__init__(message) self.message = message if status_code is not None: self.status_code = status_code self.payload = payload def to_dict(self): rv = dict(self.payload or {}) rv["error"] = self.message return rv class NotFoundError(AppError): status_code = 404 class ValidationError(AppError): status_code = 422 class AuthError(AppError): status_code = 401 @app.errorhandler(AppError) def handle_app_error(e): return jsonify(e.to_dict()), e.status_code # Usage in views: @app.get("/items/<int:id>") def get_item(id): item = db.session.get(Item, id) if not item: raise NotFoundError(f"Item {id} not found") if not current_user.can_view(item): raise AuthError("Access denied") return jsonify(item.to_dict())
Logging
Flask uses standard Python logging. The app logger is app.logger (name = app name).
app.logger.debug("Debug info: %s", value) app.logger.info("User %s logged in", user.id) app.logger.warning("Rate limit approaching for %s", ip) app.logger.error("Failed to send email: %s", exc) app.logger.exception("Unhandled error") # logs traceback at ERROR level
Configuring Logging
import logging from logging.handlers import RotatingFileHandler if not app.debug: handler = RotatingFileHandler( "logs/app.log", maxBytes=10_000_000, backupCount=5 ) handler.setLevel(logging.WARNING) handler.setFormatter(logging.Formatter( "%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]" )) app.logger.addHandler(handler) app.logger.setLevel(logging.WARNING)
Logging to Syslog / External Services
from logging.handlers import SysLogHandler syslog = SysLogHandler(address=("logs.example.com", 514)) syslog.setLevel(logging.ERROR) app.logger.addHandler(syslog)
Request Logging
import time @app.before_request def start_timer(): g.start = time.perf_counter() @app.after_request def log_request(response): duration = time.perf_counter() - g.start app.logger.info( "%s %s %s %.2fms", request.method, request.path, response.status_code, duration * 1000, ) return response
Common HTTP Exception Classes (Werkzeug)
| Class | Code | Name |
|---|---|---|
BadRequest | 400 | Bad Request |
Unauthorized | 401 | Unauthorized |
Forbidden | 403 | Forbidden |
NotFound | 404 | Not Found |
MethodNotAllowed | 405 | Method Not Allowed |
NotAcceptable | 406 | Not Acceptable |
Conflict | 409 | Conflict |
Gone | 410 | Gone |
LengthRequired | 411 | Length Required |
RequestEntityTooLarge | 413 | Request Entity Too Large |
UnsupportedMediaType | 415 | Unsupported Media Type |
UnprocessableEntity | 422 | Unprocessable Entity |
TooManyRequests | 429 | Too Many Requests |
InternalServerError | 500 | Internal Server Error |
NotImplemented | 501 | Not Implemented |
BadGateway | 502 | Bad Gateway |
ServiceUnavailable | 503 | Service Unavailable |
from werkzeug.exceptions import NotFound, Forbidden, UnprocessableEntity raise NotFound("That page does not exist") raise Forbidden() raise UnprocessableEntity("Validation failed")
Error Pages in Templates
templates/errors/ 404.html 403.html 500.html
{# templates/errors/404.html #}
{% extends "base.html" %}
{% block content %}
<h1>404 — Page Not Found</h1>
<p>{{ e.description }}</p>
<a href="{{ url_for('index') }}">Go home</a>
{% endblock %}@app.errorhandler(404) def not_found(e): return render_template("errors/404.html", e=e), 404
Propagating Exceptions in Testing
app.config["TESTING"] = True app.config["PROPAGATE_EXCEPTIONS"] = True # exceptions reach the test, not the handler
Sentry Integration
pip install sentry-sdk[flask]
import sentry_sdk from sentry_sdk.integrations.flask import FlaskIntegration sentry_sdk.init( dsn="https://your-dsn@sentry.io/project", integrations=[FlaskIntegration()], traces_sample_rate=0.2, send_default_pii=False, )
Sentry captures unhandled exceptions automatically. You can also capture manually:
from sentry_sdk import capture_exception, capture_message try: risky_operation() except Exception as e: capture_exception(e) raise