Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
always pass InternalServerError instance to 500 handler #3266
Due to multiple PRs over the last 5 years, the error handler behavior has slowly changed with the goal of being more consistent. However, after #2314 was merged in 1.0.0, these changes all cascaded together to make some inconsistent behavior finally visible.
After extensive discussion in #1281, #1291, and #1429, the goal was to make error handlers trigger for exceptions in MRO order, rather than registration order. It formalized the idea that HTTP exception classes and status codes were aliases. Registering a handler for
However, it (unintentionally?) preserved some old behavior where user errors would only be looked up against a
#2314 ensured a more consistent lookup order between blueprints and app error handlers for codes and exception classes. #2362 simplified the code even more, and made it more correct for subclass handling. A side effect of these refactors was that it fixed the preserved behavior, so 500 and
All these changes had the goal of making error handler registration and triggering more intuitive, and making maintenance easier.
When an unhandled exception is raised,
A fix was proposed in #2983 which continued to preserve the old behavior by making a handler for
Instead, I'm going the opposite direction and ensuring that those handlers only ever receive
The downside is that there is no way for this to be 100% backwards compatible for 500 handlers that were written assuming any exception would be passed to them, and I couldn't think of a way to have a useful deprecation warning transition.
While fixing this, I noticed that
To clear up related confusion about very generic error handlers such as
Looks good to me!
I think one thing worth clarifying is a case where an app registers both an
@app.errorhandler(HTTPException) def handle_http_exception(exc): if not (400 <= exc.code <= 599): # if it's not an actual error, use it as a response. # this is needed e.g. for the 301 redirects that are raised # as routing exceptions and thus end up here return exc elif exc.response: # if the exception has a custom response, we always use that # one instead of showing the default error page return exc return custom_http_error(...) @app.errorhandler(Exception) def handle_exception(exc, message=None): return custom_unhandled_error(...)
In that case I'd expect the second handler not being called for any HTTP error handled by the first one.