Error Handling & Custom Pages
Error handling in Flask is the practice of catching HTTP errors — like a missing page or a server crash — and returning your own friendly, branded response instead of the framework's bare default message.
Learn Error Handling & Custom Pages in our free Flask course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…
Part of the free Flask course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll register custom error handlers, trigger errors on purpose with abort() , and render polished 404 and 500 pages that keep users on your site instead of scaring them away.
An HTTP error is a numeric status code the server sends when something goes wrong. The browser uses it to decide what to display and how to behave.
The two you'll meet most often are 404 Not Found (the URL doesn't match any route) and 500 Internal Server Error (your code raised an unhandled exception). By default Flask shows a plain, unstyled message for these — fine for development, but jarring for real users.
The @app.errorhandler(code) decorator registers a function that Flask runs whenever that error occurs. The function should return a response and the matching status code as a tuple.
Below, the handler renders a template called 404.html and returns 404 so the browser still understands the page wasn't found. Run it and start the server with flask run to see it in action.
The error argument Flask passes in holds details about what went wrong. You usually don't need it for a simple page, but it's there if you want to log or display it.
Sometimes you decide a request should fail — for example, when a user asks for an article ID that isn't in your database. The abort(code) function stops the request immediately and raises that HTTP error, which your handler then catches.
In the example below, asking for any article other than 1 or 2 calls abort(404) , which routes straight to the custom 404 handler.
Complete the app below so it registers a 500 handler and aborts when a user is missing. Replace each ___ .
Make sure the handler returns the status code: return render_template("404.html"), 404 . Forgetting the , 404 sends a 200 and some setups skip the handler. Also confirm the function is decorated with @app.errorhandler(404) .
With debug=True , Flask shows its interactive debugger instead of your 500 page. Test custom 500 pages with debug off, and always log the real exception inside the handler.
Build a small app that protects an admin route with a 403 Forbidden error.
Lesson 14 complete — your app now fails gracefully!
You can register handlers with @app.errorhandler , raise errors on demand with abort() , and return the correct status codes so browsers and search engines stay happy.
🚀 Up next: Flashing Messages — give users instant feedback like "Saved!" or "Login failed" with Flask's flash system.
Practice quiz
Which decorator registers a custom error handler in Flask?
- @app.handle_error(code)
- @app.errorhandler(code)
- @app.on_error(code)
- @app.catch(code)
Answer: @app.errorhandler(code). @app.errorhandler(code) runs your function when that HTTP error occurs.
What HTTP status code means 'Not Found'?
- 200
- 500
- 403
- 404
Answer: 404. 404 Not Found means the URL did not match any route or resource.
What does abort(404) do?
- redirects to the home page
- logs a warning only
- stops the request and raises a 404 error
- returns an empty 200 response
Answer: stops the request and raises a 404 error. abort(code) immediately raises that HTTP error, which a handler then renders.
What status code is an Internal Server Error?
- 500
- 404
- 301
- 204
Answer: 500. 500 Internal Server Error signals an unhandled exception on the server.
How should a 404 handler return its response?
- return render_template('404.html')
- return 404
- return render_template('404.html'), 404
- raise 404
Answer: return render_template('404.html'), 404. Return a (response, status) tuple so the 404 status code is preserved.
Which status code means 'Forbidden'?
- 401
- 403
- 400
- 418
Answer: 403. 403 Forbidden means the user is authenticated but not allowed to access it.
Why must an error handler return the correct status code?
- so browsers, search engines, and clients see the right result
- to make the page load faster
- Flask requires it to compile
- to avoid importing abort
Answer: so browsers, search engines, and clients see the right result. The status code keeps the response semantically correct (a 404 should not look like a 200).
What single argument does an error handler function receive?
- the response
- the request body
- the template name
- the error object
Answer: the error object. Flask passes the error/exception object, useful for logging the failure.
Why might a custom 500 page not show during development?
- debug=True shows the interactive debugger instead
- 500 cannot be handled
- render_template is disabled
- Flask caches the 200 page
Answer: debug=True shows the interactive debugger instead. With debug=True Flask shows its debugger; test 500 pages with debug off.
How do you raise a Forbidden error deliberately?
- abort(403)
- raise Forbidden
- return 403
- deny(403)
Answer: abort(403). abort(403) raises a 403, routed to your @app.errorhandler(403).