Users and API clients deserve clear, consistent errors instead of default pages or stack traces.
abort(status) raises an HTTPException that immediately ends the request with that status. Use it for guard clauses: abort(404) when a record doesn't exist, abort(403) when the user isn't allowed. You can pass a description: abort(400, description="missing email").
Without handlers, Flask sends Werkzeug's plain HTML error pages. Register your own with @app.errorhandler, keyed by status code or exception class:
@app.errorhandler(404)
def not_found(e):
return render_template("404.html"), 404Return the status code explicitly; the handler's response is otherwise a 200.
For a JSON API, one handler for HTTPException covers every HTTP error: read e.code, e.name and e.description and return them as JSON.
Unhandled exceptions in your code become 500 Internal Server Error. In debug mode you see the traceback; in production the user sees the 500 page (customize it with @app.errorhandler(500)) and the exception is logged to app.logger. You can also register handlers for your own exception classes, such as NotFoundError raised by a service layer, and translate them into HTTP responses in one place.
Handlers registered on the app apply everywhere. Blueprints can register their own, which take precedence for errors raised inside the blueprint's views, though 404 and 405 come from routing and are only handled by app-level handlers.
Example
from flask import Flask, abort
from werkzeug.exceptions import HTTPException
app = Flask(__name__)
BOOKS = {1: "Dune"}
@app.get("/books/<int:bid>")
def book(bid):
if bid not in BOOKS:
abort(404, description=f"no book {bid}")
return {"title": BOOKS[bid]}
@app.get("/boom")
def boom():
return 1 / 0
@app.errorhandler(HTTPException)
def http_error(e):
return {"error": e.name, "detail": e.description}, e.code
@app.errorhandler(ZeroDivisionError)
def math_error(e):
return {"error": "calculation failed"}, 500
c = app.test_client()
print(c.get("/books/9").json) # {'detail': 'no book 9', 'error': 'Not Found'}
print(c.get("/boom").status_code) # 500Remember
- abort(code) ends a request immediately with an HTTP error
- @app.errorhandler(code or exception class) customizes the response
- Handlers must return the status code themselves
Watch out for
- Forgetting the status in an error handler, so the custom 404 page is sent as 200.