The Fix
Upgrade to version 0.12.3 or later.
Based on closed pallets/flask issue #2267 · PR/commit linked
@@ -76,6 +76,9 @@ Major release, unreleased
classes used by Flask. This adds the ``is_json`` and ``get_json`` methods to
the response to make testing JSON response much easier. (`#2358`_)
+- Removed error handler caching because it caused unexpected results for some
+ exception inheritance hierarchies. Register handlers explicitly for each
+ exception if you don't want to traverse the MRO. (`#2362`_)
from flask import Flask
from werkzeug.exceptions import InternalServerError
class E1(Exception):
pass
class E2(Exception):
pass
class E(E1, E2):
pass
app = Flask(__name__)
@app.errorhandler(E2)
def handle_e2(e):
return "E2", 500
@app.errorhandler(Exception)
def handle_exception(e):
return "Exception", 500
@app.route("/<exception>", methods=['POST'])
def raise_exception(exception):
exc = globals()[exception]
raise exc
def test_errorhandler_precedence():
client = app.test_client()
response1 = client.post('/E1')
assert response1.data == "Exception"
response2 = client.post('/E')
assert response2.data == "E2"
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Option A — Upgrade to fixed release\nUpgrade to version 0.12.3 or later.\nWhen NOT to use: Do not use this fix if you rely on caching for performance in exception handling.\n\n
Why This Fix Works in Production
- Trigger: Flask error handler caching leads to inconsistent behavior
- Mechanism: Error handler caching in Flask led to incorrect behavior for exception subclasses due to MRO traversal
- Why the fix works: Removed error handler caching to prevent inconsistent behavior with exception inheritance in Flask. (first fixed release: 0.12.3).
- If left unfixed, this can cause silent data inconsistencies that propagate (bad cache entries, incorrect downstream decisions).
Why This Breaks in Prod
- Error handler caching in Flask led to incorrect behavior for exception subclasses due to MRO traversal
- Production symptom (often without a traceback): Flask error handler caching leads to inconsistent behavior
Proof / Evidence
- GitHub issue: #2267
- Fix PR: https://github.com/pallets/flask/pull/2362
- First fixed release: 0.12.3
- Reproduced locally: No (not executed)
- Last verified: 2026-02-09
- Confidence: 0.80
- Did this fix it?: Yes (upstream fix exists)
- Own content ratio: 0.45
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“When Flask finds an error handler for a given exception, it caches it in the handler map. This can lead to incorrect behavior for subclasses of the exception. Here is some code demonstrating the problem: In this example, we have two excepti”
Failure Signature (Search String)
- Flask error handler caching leads to inconsistent behavior
- When Flask finds an error handler for a given exception, it caches it in the handler map. This can lead to incorrect behavior for subclasses of the exception.
Copy-friendly signature
Failure Signature
-----------------
Flask error handler caching leads to inconsistent behavior
When Flask finds an error handler for a given exception, it caches it in the handler map. This can lead to incorrect behavior for subclasses of the exception.
Error Message
Signature-only (no traceback captured)
Error Message
-------------
Flask error handler caching leads to inconsistent behavior
When Flask finds an error handler for a given exception, it caches it in the handler map. This can lead to incorrect behavior for subclasses of the exception.
Minimal Reproduction
from flask import Flask
from werkzeug.exceptions import InternalServerError
class E1(Exception):
pass
class E2(Exception):
pass
class E(E1, E2):
pass
app = Flask(__name__)
@app.errorhandler(E2)
def handle_e2(e):
return "E2", 500
@app.errorhandler(Exception)
def handle_exception(e):
return "Exception", 500
@app.route("/<exception>", methods=['POST'])
def raise_exception(exception):
exc = globals()[exception]
raise exc
def test_errorhandler_precedence():
client = app.test_client()
response1 = client.post('/E1')
assert response1.data == "Exception"
response2 = client.post('/E')
assert response2.data == "E2"
What Broke
Inconsistent error responses when raising exceptions due to cached handlers.
Why It Broke
Error handler caching in Flask led to incorrect behavior for exception subclasses due to MRO traversal
Fix Options (Details)
Option A — Upgrade to fixed release Safe default (recommended)
Upgrade to version 0.12.3 or later.
Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.
Fix reference: https://github.com/pallets/flask/pull/2362
First fixed release: 0.12.3
Last verified: 2026-02-09. Validate in your environment.
When NOT to Use This Fix
- Do not use this fix if you rely on caching for performance in exception handling.
Verify Fix
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Did This Fix Work in Your Case?
Quick signal helps us prioritize which fixes to verify and improve.
Prevention
- Capture the exact failing error string in logs and tests so you can reproduce via a minimal script.
- Pin production dependencies and upgrade only with a reproducible test that hits the failing path.
Version Compatibility Table
| Version | Status |
|---|---|
| 0.12.3 | Fixed |
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.