{"record":{"id":"a3107118311618bb","repo":"pytest-dev/pytest","slug":"request-fixturename-did-not-yield-a-value","errorCode":null,"errorMessage":"{request.fixturename} did not yield a value","messagePattern":"(.+?) did not yield a value","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/_pytest/fixtures.py","lineNumber":1061,"sourceCode":"            for line in lines[1:]:\n                tw.line(\n                    f\"{ExceptionInfoFormatter.flow_marker}       {line.strip()}\",\n                    red=True,\n                )\n        tw.line()\n        tw.line(f\"{os.fspath(self.filename)}:{self.firstlineno + 1}\")\n\n\ndef call_fixture_func(\n    fixturefunc: _FixtureFunc[FixtureValue], request: FixtureRequest, kwargs\n) -> FixtureValue:\n    if inspect.isgeneratorfunction(fixturefunc):\n        fixturefunc = cast(Callable[..., Generator[FixtureValue]], fixturefunc)\n        generator = fixturefunc(**kwargs)\n        try:\n            fixture_result = next(generator)\n        except StopIteration:\n            raise ValueError(f\"{request.fixturename} did not yield a value\") from None\n        finalizer = functools.partial(_teardown_yield_fixture, fixturefunc, generator)\n        request.addfinalizer(finalizer)\n    else:\n        fixturefunc = cast(Callable[..., FixtureValue], fixturefunc)\n        fixture_result = fixturefunc(**kwargs)\n    return fixture_result\n\n\ndef _teardown_yield_fixture(fixturefunc, it) -> None:\n    \"\"\"Execute the teardown of a fixture function by advancing the iterator\n    after the yield and ensure the iteration ends (if not it means there is\n    more than one yield in the function).\"\"\"\n    try:\n        next(it)\n    except StopIteration:\n        pass\n    else:\n        fs, lineno = getfslineno(fixturefunc)","sourceCodeStart":1043,"sourceCodeEnd":1079,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/fixtures.py#L1043-L1079","documentation":"At fixtures.py:1061 a generator-based fixture (one using 'yield') raised StopIteration on the first next() call, meaning the function executed without reaching any 'yield' statement. pytest wraps this as ValueError('{fixturename} did not yield a value') so teardown is not registered on an empty generator. The fixture must always reach a yield when written in generator style.","triggerScenarios":"A fixture decorated with @pytest.fixture whose body uses 'yield' but a conditional branch returns or raises before the yield; a 'yield' inside an if/for block that is skipped; early 'return' before yield in a generator fixture.","commonSituations":"Guard clauses (if not enabled: return) in a yield-fixture that skip the yield; refactoring a return-style fixture to yield-style but missing the yield on some path; skip/pytest.exit calls before yield.","solutions":["Ensure every code path through the fixture reaches the 'yield' statement.","Move guard logic so the yield still executes (yield a sentinel/default value if needed) instead of returning early.","If conditional teardown is needed, yield first then branch on teardown logic after yield.","Use a non-generator fixture (plain return) if no teardown is required."],"exampleFix":"// before\n@pytest.fixture\ndef client():\n    if not ENABLED:\n        return  # skips yield -> error\n    c = make_client()\n    yield c\n    c.close()\n// after\n@pytest.fixture\ndef client():\n    if not ENABLED:\n        yield None\n        return\n    c = make_client()\n    yield c\n    c.close()","handlingStrategy":"validation","validationCode":"# Static check: ensure every @pytest.fixture with 'yield' reaches it on all paths.\n# Use AST scan in a pre-commit hook.\nimport ast, pathlib\nfor f in pathlib.Path('tests').rglob('test_*.py'):\n    tree = ast.parse(f.read_text())\n    # naive: flag any fixture func with 'return' before 'yield' (use a linter rule)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always place 'yield' as the last statement before teardown, after all guards.","Prefer plain-return fixtures when no teardown is needed.","Use a linter (flake8-pytest-style) to enforce fixture shape."],"tags":["pytest","fixtures","generator","yield","control-flow"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}