pytest-dev/pytest · error · ValueError
{request.fixturename} did not yield a value
Error message
{request.fixturename} did not yield a value What it means
Raised in `call_fixture_func` when a generator-style fixture function (one containing `yield`) returns without ever yielding a value (StopIteration on the first `next()`). pytest treats generator fixtures as setup/teardown pairs and requires exactly one yielded value, so a generator that exits before yielding has no setup value to inject.
Source
Thrown at src/_pytest/fixtures.py:1061
for line in lines[1:]:
tw.line(
f"{ExceptionInfoFormatter.flow_marker} {line.strip()}",
red=True,
)
tw.line()
tw.line(f"{os.fspath(self.filename)}:{self.firstlineno + 1}")
def call_fixture_func(
fixturefunc: _FixtureFunc[FixtureValue], request: FixtureRequest, kwargs
) -> FixtureValue:
if inspect.isgeneratorfunction(fixturefunc):
fixturefunc = cast(Callable[..., Generator[FixtureValue]], fixturefunc)
generator = fixturefunc(**kwargs)
try:
fixture_result = next(generator)
except StopIteration:
raise ValueError(f"{request.fixturename} did not yield a value") from None
finalizer = functools.partial(_teardown_yield_fixture, fixturefunc, generator)
request.addfinalizer(finalizer)
else:
fixturefunc = cast(Callable[..., FixtureValue], fixturefunc)
fixture_result = fixturefunc(**kwargs)
return fixture_result
def _teardown_yield_fixture(fixturefunc, it) -> None:
"""Execute the teardown of a fixture function by advancing the iterator
after the yield and ensure the iteration ends (if not it means there is
more than one yield in the function)."""
try:
next(it)
except StopIteration:
pass
else:
fs, lineno = getfslineno(fixturefunc)View on GitHub (pinned to 98b357f69e)
Solutions
- Ensure the generator always reaches exactly one `yield` on every code path; move guards outside the fixture or use pytest.mark.skip.
- If you sometimes have nothing to provide, yield a sentinel (e.g. `yield None`) unconditionally.
- Split conditional setup into a non-generator fixture returning a value and a separate teardown via `request.addfinalizer`.
Example fix
// before
@pytest.fixture
def conn(request):
if not ENABLED:
return # -> did not yield a value
c = open()
yield c
c.close()
// after
@pytest.fixture
def conn(request):
if not ENABLED:
pytest.skip("disabled")
c = open()
yield c
c.close() Defensive patterns
Strategy: validation
Validate before calling
import inspect
def safe_fixture(fn):
if inspect.isgeneratorfunction(fn):
gen = fn()
try:
next(gen)
except StopIteration:
raise ValueError(f"{fn.__name__} did not yield")
return fn Type guard
def always_yields(fn) -> bool:
import ast, inspect
if not inspect.isgeneratorfunction(fn):
return True
tree = ast.parse(inspect.getsource(fn))
return any(isinstance(n, ast.Yield) for n in ast.walk(tree)) Prevention
- Ensure every code path in a generator fixture reaches exactly one yield.
- Use pytest.skip() instead of early return for conditional fixtures.
- Yield a sentinel (None) when there is nothing to provide.
When it happens
Trigger: A `@pytest.fixture` generator function that conditionally returns before the yield, e.g. `def f():\n if skip: return\n yield 1`, or an accidentally empty generator. The first `next()` raises StopIteration which pytest converts to ValueError naming the fixture.
Common situations: Adding an early `return` guard for a conditional skip inside a yielding fixture. Refactoring a fixture so the yield is inside an `if` branch. Misplaced `return` instead of `continue`.
Related errors
- class fixtures not supported (maybe in the future)
- @pytest.fixture is being applied more than once to the same
- function not available in {self.scope}-scoped context
- cls not available in {self.scope}-scoped context
- module not available in {self.scope}-scoped context
AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04).
Data as JSON: /data/errors/a3107118311618bb.json.
Report an issue: GitHub.