Bug: _CollectErrors silently discards teardown errors on Python < 3.11
Markdown
On Python versions prior to 3.11, `_CollectErrors.raise_any()` (in `src/flask/helpers.py`, line 682) only re-raises the very first collected error, silently swallowing any subsequent teardown errors. This makes debugging secondary teardown failures impossible on Python < 3.11.
### How to replicate the bug
1. Create a `_CollectErrors` context manager.
2. Trigger multiple teardown exceptions (e.g., DB close fails, then Cache flush fails).
3. Call `raise_any()`. Only the first exception is raised; the others are silently lost.
**Minimal Reproducible Example:**
```python
import sys
class _CollectErrors:
def __init__(self):
self.errors = []
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_val is not None:
self.errors.append(exc_val)
return True
def raise_any(self, message: str) -> None:
if self.errors:
if sys.version_info >= (3, 11):
raise BaseExceptionGroup(message, self.errors)
else:
raise self.errors[0] # BUG: only first error raised
collect = _CollectErrors()
with collect:
raise RuntimeError("DB connection close failed")
with collect:
raise ValueError("File handle close failed")
try:
collect.raise_any("Teardown errors")
except Exception as e:
print(f"Raised: {type(e).__name__}: {e}")
print(f"Total collected: {len(collect.errors)}")
```
Expected behavior
Even without BaseExceptionGroup (which is 3.11+), subsequent errors should not be silently discarded. They should ideally be chained or at least logged before raising the first error.
Proposed Fix
Consider chaining the exceptions or logging the secondary ones before raising the first on Python versions < 3.11.
Environment:
Python version: < 3.11 (e.g., 3.10)
Flask version: 3.2.0.dev (flask-main branch)
1 条评论