pytest-dev/pytest · error · BaseExceptionGroup
errors during test teardown
Error message
errors during test teardown
What it means
Raised as a BaseExceptionGroup by SetupState.teardown_exact when more than one exception is collected while popping and running finalizers from the fixture/test stack at the end of a test. pytest groups the per-node teardown failures into a single exception group so teardown errors from sibling fixtures are not silently lost. Each subgroup's message is 'errors while tearing down <node>'.
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 98b357f69e)
Solutions
- Inspect the ExceptionGroup's sub-exceptions (use `except*` on Python 3.11+, or `e.exceptions`) to identify each root cause individually.
- Make each fixture teardown defensive: wrap cleanup bodies in try/except so one failing finalizer cannot mask others or cascade.
- Reproduce teardown in isolation by running only the failing test with `-p no:randomly` and `--setup-show` to see fixture order.
- Ensure resource handles (files, sockets, subprocesses) are closed in finally blocks rather than bare yield fixtures.
Example fix
// before
@pytest.fixture
def db():
conn = open_conn()
yield conn
conn.close() # raises if conn is broken, masks other teardown errors
// after
@pytest.fixture
def db():
conn = open_conn()
try:
yield conn
finally:
try:
conn.close()
except Exception:
pass # log and continue; let other finalizers run Defensive patterns
Strategy: try-catch
Try / catch
# Python 3.11+
try:
run_test(item)
except* Exception as eg:
for e in eg.exceptions:
log_teardown_failure(e)
# Python < 3.11
try:
run_test(item)
except BaseExceptionGroup as eg:
for e in eg.exceptions:
log_teardown_failure(e) Prevention
- Wrap each fixture's post-yield cleanup in try/finally so one failure cannot cascade.
- Use addfinalizer or yield fixtures consistently; mixing styles complicates teardown order.
- Run with --setup-show during development to visualize teardown order and catch leaks early.
When it happens
Trigger: Two or more fixture finalizers (yield fixtures' post-yield code, addfinalizer callbacks, autouse fixture teardowns) raise during teardown of the same test item, or finalizers across different nodes in the stack all fail. TEST_OUTCOME exceptions (AssertionError, Exception, Skip, etc.) are captured and bundled here.
Common situations: A fixture's cleanup hits an assertion, while a dependent fixture also fails to close a resource; switching from a passing to a failing test where multiple teardowns now misbehave; plugin finalizers interacting with broken state left by the failing test body.
Related errors
- errors while tearing down fixture "{self.argname}" of {node}
- The fixture value for "{argname}" is not available during te
- multiple thread exception warnings
- Unittest class cleanup errors
- multiple unraisable exception warnings
AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04).
Data as JSON: /data/errors/1bf611b3124e735a.json.
Report an issue: GitHub.