ITADN

Bug: _CollectErrors silently discards teardown errors on Python < 3.11

#6044OpenRajib-Mahmud 创建于 2026-06-05
R
Rajib-Mahmudcommented
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 条评论