sebastianbergmann/phpunit · error · NoMoreReturnValuesConfiguredException
Only %d return values have been configured for %s::%s()
Error message
Only %d return values have been configured for %s::%s()
What it means
ConsecutiveCalls is the stub behind willReturnOnConsecutiveCalls() (and deprecated withConsecutive()/willReturnMap-style sequential stubbing): it hands out one configured return value per invocation, in order. When the mocked method is invoked more times than the number of values you configured, the internal stack is empty and PHPUnit throws NoMoreReturnValuesConfiguredException, reporting how many values were originally configured so you can see the mismatch between configured values and actual call count.
Source
Thrown at src/Framework/MockObject/Runtime/Stub/ConsecutiveCalls.php:45
private array $stack;
private int $numberOfConfiguredReturnValues;
/**
* @param array<mixed> $stack
*/
public function __construct(array $stack)
{
$this->stack = $stack;
$this->numberOfConfiguredReturnValues = count($stack);
}
/**
* @throws NoMoreReturnValuesConfiguredException
*/
public function invoke(Invocation $invocation): mixed
{
if ($this->stack === []) {
throw new NoMoreReturnValuesConfiguredException(
$invocation,
$this->numberOfConfiguredReturnValues,
);
}
$value = array_shift($this->stack);
if ($value instanceof Stub) {
$value = $value->invoke($invocation);
}
return $value;
}
}
View on GitHub (pinned to f123cdb2a2)
Solutions
- Append the missing trailing return value(s) — most often a terminating value such as null, false, or [] so loops in the SUT stop calling.
- Replace willReturnOnConsecutiveCalls() with willReturnCallback() or returnValueMap() when call count is unpredictable: map arguments to returns, or generate values until a stop condition.
- Reduce the number of calls the SUT makes (fix the loop/retry bound in production code) if the extra call is itself the defect.
- For generated mocks, keep auto return value generation in mind: only methods with an explicit consecutive stub consume the stack, so narrowing onlyMethods() can stop the exhausted stub from being hit.
Example fix
// before
$api->method('loadPage')
->willReturnOnConsecutiveCalls($page1, $page2);
// SUT loops until null -> third call throws NoMoreReturnValuesConfiguredException
// after
$api->method('loadPage')
->willReturnOnConsecutiveCalls($page1, $page2, null); // terminator stops the loop Defensive patterns
Strategy: validation
Validate before calling
// Guard before the SUT runs when call count is data-driven:
$iterations = count($items) + 1; // how many times fetch() will be called
$values = array_map(fn ($i) => $pages[$i] ?? null, range(0, $iterations - 1));
$api->method('loadPage')->willReturnOnConsecutiveCalls(...$values); Try / catch
use PHPUnit\Framework\MockObject\NoMoreReturnValuesConfiguredException;
try {
$result = $sut->drain();
} catch (NoMoreReturnValuesConfiguredException $e) {
self::fail('Stub ran out of values: ' . $e->getMessage());
} Prevention
- Always end consecutive value lists with the SUT's loop terminator (null, false, []).
- Compute the value list from the same count the SUT will iterate, not a hand-typed literal.
- Prefer willReturnCallback() when the number of calls is open-ended.
- When adding a warm-up/seed call to the SUT, prepend (not append) its return value to every consecutive list in affected tests.
When it happens
Trigger: $mock->method('fetch')->willReturnOnConsecutiveCalls('a', 'b') followed by three or more calls to $mock->fetch(): the first two calls consume 'a' and 'b', the third call finds $this->stack === [] in ConsecutiveCalls::invoke() and throws. Typical with loops, retries, pagination, or queue-draining code under test that iterates more often than the test's value list covers.
Common situations: Retry logic that now attempts one extra round; a paginator that keeps calling until null/empty is returned while the test forgot to append a terminating return value (null, false, []); adding a warm-up call in a refactor; data-provider datasets where one case produces more iterations than the consecutive values list anticipates.
Related errors
- No entry in the value map matched the invocation of %s::%s()
- Not enough parameter sets configured, only %d parameter sets
- Not enough parameter sets configured, only %d parameter sets
- Not enough parameter sets configured, only %d parameter sets
- %d out of %d expected unordered parameter set%s %s called, i
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/40e0a42afafea7bf.
Report an issue: GitHub.