diff --git a/src/flask/app.py b/src/flask/app.py index 652b9bbf71..93dfd0d2e7 100644 --- a/src/flask/app.py +++ b/src/flask/app.py @@ -1601,7 +1601,11 @@ def wsgi_app( except: error = sys.exc_info()[1] raise - return response(environ, start_response) + try: + return response(environ, start_response) + except BaseException as e: + error = e + raise finally: if "werkzeug.debug.preserve_context" in environ: environ["werkzeug.debug.preserve_context"](ctx) diff --git a/tests/test_basic.py b/tests/test_basic.py index 1d9d83f8cb..7853fdb0dc 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -1968,3 +1968,29 @@ def test_app_freed_on_zero_refcount(): assert weak() is None finally: gc.enable() + + +def test_teardown_receives_wsgi_response_error(app, client): + """Teardown functions receive the exception when + response(environ, start_response) raises during WSGI response + delivery, not exc=None.""" + + @app.teardown_request + def teardown(exc): + app.config["_teardown_exc"] = exc + + class FailingResponse(flask.Response): + def __call__(self, environ, start_response): + raise RuntimeError("response delivery failed") + + @app.route("/") + def index(): + return FailingResponse("ok") + + try: + client.get("/") + except RuntimeError: + pass + + assert app.config.get("_teardown_exc") is not None + assert isinstance(app.config["_teardown_exc"], RuntimeError)