{"record":{"id":"5bd26589b2af6b77","repo":"pytest-dev/pytest","slug":"errors-while-tearing-down-fixture-self-argname","errorCode":null,"errorMessage":"errors while tearing down fixture \"{self.argname}\" of {node}","messagePattern":"errors while tearing down fixture \"(.+?)\" of (.+?)","errorType":"exception","errorClass":"BaseExceptionGroup","httpStatus":null,"severity":"error","filePath":"src/_pytest/fixtures.py","lineNumber":1230,"sourceCode":"\n        exceptions: list[BaseException] = []\n        while self._finalizers:\n            fin = self._finalizers.pop()\n            try:\n                fin()\n            except BaseException as e:\n                exceptions.append(e)\n        node = request.node\n        # Even if finalization fails, we invalidate the cached fixture\n        # value and remove all finalizers because they may be bound methods\n        # which will keep instances alive.\n        self.cached_result = None\n        self._finalizers.clear()\n        if len(exceptions) == 1:\n            raise exceptions[0]\n        elif len(exceptions) > 1:\n            msg = f'errors while tearing down fixture \"{self.argname}\" of {node}'\n            raise BaseExceptionGroup(msg, exceptions[::-1])\n\n    def execute(self, request: SubRequest) -> FixtureValue:\n        \"\"\"Return the value of this fixture, executing it if not cached.\"\"\"\n        # Ensure that the dependent fixtures requested by this fixture are loaded.\n        # This needs to be done before checking if we have a cached value, since\n        # if a dependent fixture has their cache invalidated, e.g. due to\n        # parametrization, they finalize themselves and fixtures depending on it\n        # (which will likely include this fixture) setting `self.cached_result = None`.\n        # See #4871\n        requested_fixtures_that_should_finalize_us = []\n        for argname in self.argnames:\n            fixturedef = request._get_active_fixturedef(argname)\n            # Saves requested fixtures in a list so we later can add our finalizer\n            # to them, ensuring that if a requested fixture gets torn down we get torn\n            # down first. This is generally handled by SetupState, but still currently\n            # needed when this fixture is not parametrized but depends on a parametrized\n            # fixture.\n            requested_fixtures_that_should_finalize_us.append(fixturedef)","sourceCodeStart":1212,"sourceCodeEnd":1248,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/fixtures.py#L1212-L1248","documentation":"At fixtures.py:1230 pytest raises BaseExceptionGroup('errors while tearing down fixture ...') when TWO OR MORE exceptions occur while running a fixture's registered finalizers. Single exceptions are re-raised as-is; multiple are grouped (reversed to reflect execution order) so teardown failures are not hidden. The fixture's cached_result and finalizers are cleared before raising.","triggerScenarios":"A yield-fixture whose post-yield teardown and one or more addfinalizer callbacks all raise; multiple dependencies of a fixture fail teardown simultaneously; teardown code calling external resources (DB close, file unlock) that error.","commonSituations":"Cleanup code hitting already-closed resources; finalizers that depend on side effects from other failing finalizers; test environments where multiple external services are torn down and several are unreachable.","solutions":["Inspect the BaseExceptionGroup.subgroups/exceptions to find each root cause; fix the most fundamental one first.","Make each teardown step defensive (try/except inside the finalizer) so one failure does not cascade.","Use context managers / addfinalizer per-resource to isolate teardown scope.","Reproduce with -p no:randomly and a single test to reduce concurrency-induced multi-failures."],"exampleFix":"// before\n@pytest.fixture\ndef svc():\n    yield start()\n    stop_db()   # may raise\n    stop_cache()# also raises -> group\n// after\n@pytest.fixture\ndef svc():\n    yield start()\n    for closer in (stop_db, stop_cache):\n        try:\n            closer()\n        except Exception as e:\n            logging.warning('teardown failed: %s', e)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"# In conftest.py, make teardown resilient\nimport pytest, logging\n@pytest.fixture(autouse=True)\ndef _safe_teardown():\n    yield\n    # user teardown handled per-fixture below","preventionTips":["Wrap each teardown step in try/except and log instead of raising.","Isolate resource teardown with context managers.","Run flaky teardowns with -p no:randomly to reduce ordering-induced multi-failures."],"tags":["pytest","fixtures","teardown","exceptiongroup","finalizers"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}