sebastianbergmann/phpunit · error · NeverReturningMethodException
Method %s::%s() is declared to never return
Error message
Method %s::%s() is declared to never return
What it means
Thrown by Invocation::generateReturnValue() when a method whose declared return type is 'never' is actually invoked on a double and no explicit stub action produced a return before this point. PHP semantics say a never-returning method must throw or exit; PHPUnit turns the attempt to fabricate a default return value into this explicit exception naming the class and method.
Source
Thrown at src/Framework/MockObject/Runtime/Invocation.php:102
{
return $this->methodName;
}
/**
* @return array<mixed>
*/
public function parameters(): array
{
return $this->parameters;
}
/**
* @throws Exception
*/
public function generateReturnValue(): mixed
{
if ($this->returnType === 'never') {
throw new NeverReturningMethodException(
$this->className,
$this->methodName,
);
}
if ($this->isReturnTypeNullable) {
return null;
}
return (new ReturnValueGenerator)->generate(
$this->className,
$this->methodName,
$this->object,
$this->returnType,
);
}
public function toString(): stringView on GitHub (pinned to f123cdb2a2)
Solutions
- Make the expectation explicit that the call ends the flow: ->will($this->throwException(new \LogicException('should not happen'))).
- If the call is legitimate in the tested path, refactor the code under test so the never-method is not relied upon to return.
- If you expect the method not to be called, keep expects($this->never()) and fix the production code that reaches it.
Example fix
// before
$guard = $this->createStub(Guard::class);
$guard->method('abort'); // abort(): never — no action configured
// after
$guard = $this->createStub(Guard::class);
$guard->method('abort')
->will($this->throwException(new \RuntimeException('aborted'))); Defensive patterns
Strategy: validation
Validate before calling
$rm = new ReflectionMethod(Guard::class, 'abort');
if ((string) $rm->getReturnType() === 'never') {
// never rely on default return generation for this method
$stub->method('abort')->will($this->throwException(new \RuntimeException('abort')));
} Type guard
function isNeverReturning(ReflectionMethod $m): bool
{
return (string) $m->getReturnType() === 'never';
} Try / catch
try {
$subject->run($stub);
} catch (PHPUnit\Framework\MockObject\NeverReturningMethodException $e) {
// the code reached a path that calls a never-method — treat as control flow
} Prevention
- Audit stubbed APIs for : never methods (fail/abort helpers) and always attach a throwing stub action.
- Model never-methods with ->will($this->throwException(...)), never with default generation.
- Track upstream changes from void to never in dependencies you stub.
When it happens
Trigger: The code under test calls a never-typed method on a mock/stub (e.g. a fatal-fail() helper declared : never) and the expectation has no will(...)/willReturnCallback(...) that throws; a generic fallback in InvocationHandler reaches generateReturnValue() for that invocation.
Common situations: Domain libraries declaring fail()/abort()/mustNotExist() helpers as : never; value objects with invariant guards; tests stubbing such helpers with expects($this->once()) only, then production code actually reaching the failure path; upgrading a dependency that changed a void helper to never.
Related errors
- Return value for %s::%s() cannot be generated%s, please conf
- Return value for %s::%s() cannot be generated: %s
- Cannot double method with invalid name "%s"
- Cannot double using a method list that contains duplicates:
- Cannot use "%s" as the name of a test double class because i
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/2bdf5758d26f41af.
Report an issue: GitHub.