pytest-dev/pytest · error · BaseExceptionGroup
errors during test teardown
Error message
errors during test teardown
What it means
Not a raised exception object per se but the message of the BaseExceptionGroup propagated by SetupState.teardown_exact when multiple finalizers/teardowns across one or more nodes raise. Each failing finalizer is collected; if there is more than one across the whole teardown, they are bundled into a BaseExceptionGroup titled 'errors during test teardown' (a per-node group is titled 'errors while tearing down {node}'). This surfaces every teardown failure rather than just the first.
Solutions
- Inspect the BaseExceptionGroup's .exceptions list to see each teardown failure individually.
- Make each finalizer defensive (try/except inside, log and continue) so one failure does not mask others.
- Fix the root-cause finalizer first; re-run to confirm remaining failures clear.
- Use pytest --tb=short or -rA to render every teardown error in the summary.
Example fix
// before
@pytest.fixture
def conn():
c = open_conn()
yield c
c.close() # raises if conn never opened
// after
@pytest.fixture
def conn():
c = open_conn()
try:
yield c
finally:
try:
c.close()
except Exception:
logger.exception('teardown close failed') Defensive patterns
Strategy: try-catch
Validate before calling
import contextlib, traceback
# pattern for finalizers: never let one mask another
def safe_finalizer(fn, *a, **k):
try:
return fn(*a, **k)
except Exception:
traceback.print_exc()
return None Try / catch
@pytest.fixture
def resource():
r = open_resource()
try:
yield r
finally:
try:
r.close()
except Exception:
logger.exception('resource.close failed during teardown') Prevention
- Wrap each fixture's post-yield teardown in try/except so one failure does not mask others.
- Inspect BaseExceptionGroup.exceptions to enumerate every teardown failure. Use -rA / --tb=short to surface all teardown errors in the summary.
- Order finalizers to release resources in reverse acquisition order to minimize cascading failures.
When it happens
Trigger: Two or more pytest fixtures' finalizers (or teardown methods) raising during teardown_exact; a single node with multiple failing finalizers produces the 'errors while tearing down {node}' inner group, and multiple such nodes are aggregated under 'errors during test teardown'.
Common situations: Fixture finalizers that close resources which were never opened; teardown calling external services that are down; yield-based fixtures where the post-yield code raises; cascading failures in session/module/function scopes.
Related errors
- errors while tearing down fixture
- class fixtures not supported (maybe in the future)
- Error evaluating while defining fixture ' '. Expected a…
- import error in
- Only `ExceptionGroup[Exception]` or…
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/1bf611b3124e735a.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/runner.py:581
node, (finalizers, _) = self.stack.popitem()
these_exceptions = []
while finalizers:
fin = finalizers.pop()
try:
fin()
except TEST_OUTCOME as e:
these_exceptions.append(e)
if len(these_exceptions) == 1:
exceptions.extend(these_exceptions)
elif these_exceptions:
msg = f"errors while tearing down {node!r}"
exceptions.append(BaseExceptionGroup(msg, these_exceptions[::-1]))
if len(exceptions) == 1:
raise exceptions[0]
elif exceptions:
raise BaseExceptionGroup("errors during test teardown", exceptions[::-1])
if nextitem is None:
assert not self.stack
def collect_one_node(collector: Collector) -> CollectReport:
ihook = collector.ihook
ihook.pytest_collectstart(collector=collector)
rep: CollectReport = ihook.pytest_make_collect_report(collector=collector)
call = rep.__dict__.pop("call", None)
if call and check_interactive_exception(call, rep):
ihook.pytest_exception_interact(node=collector, call=call, report=rep)
return rep
View on GitHub (pinned to 0d6fbdeffa)