Error Pages
Things go wrong. Pages get moved, servers hiccup, users type the wrong URL. Without custom error pages, your visitors see an ugly default page that screams "amateur." With custom error handlers, you can show something helpful and keep users on your site instead of bouncing.
Handling 404 Not Found
The 404 error is the most common โ it happens when someone requests a page that doesn't exist. Catch it and show something useful.
@app.errorhandler(404)
def page_not_found(e):
return render_template('errors/404.html'), 404
The second return value is the HTTP status code. Without it, Flask would return 200, which tells the browser everything is fine when it clearly isn't. Always include the correct status code.
Handling 500 Internal Server Error
The 500 error means something broke on the server side. This is your safety net โ show a friendly page instead of a stack trace.
@app.errorhandler(500)
def internal_server_error(e):
return render_template('errors/500.html'), 500
In production, you'd also want to log the error so you can fix whatever caused it. Flask can log to a file or external service automatically.
Custom Error Templates
Your error pages should look like the rest of your site. Keep the header, footer, and styling consistent so users don't feel like they've left your app.
<!-- templates/errors/404.html -->
{% extends "base.html" %}
{% block content %}
<div class="error-page">
<h1>404 - Page Not Found</h1>
<p>The page you're looking for doesn't exist.</p>
<a href="/">Go back home</a>
</div>
{% endblock %}
Extend your base template so the error page feels like a natural part of your site. Add a helpful message and a link back to safety.
JSON Errors for APIs
If your app serves an API, error responses should be JSON too. You can use Accept headers or just check the request type.
@app.errorhandler(404)
def not_found(e):
if request.path.startswith('/api/'):
return jsonify({'error': 'Not found'}), 404
return render_template('errors/404.html'), 404
@app.errorhandler(500)
def server_error(e):
if request.path.startswith('/api/'):
return jsonify({'error': 'Internal server error'}), 500
return render_template('errors/500.html'), 500
Error Logging
Custom error pages are great for users, but you still need to know what went wrong. Log errors so you can fix them.
import logging
logging.basicConfig(filename='app.log', level=logging.ERROR)
@app.errorhandler(500)
def internal_server_error(e):
logging.error(f'Server error: {e}')
return render_template('errors/500.html'), 500
In production, you'd use a logging service like Sentry or integrate with your monitoring stack. The important thing is that errors don't silently disappear.
Graceful Degradation
Custom error pages are about graceful degradation. Something went wrong, but your app handles it professionally. Users see a helpful message, API clients get a clear error response, and you get logged details to fix the issue. It's the difference between a polished app and a half-finished project.