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(): string

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Make the expectation explicit that the call ends the flow: ->will($this->throwException(new \LogicException('should not happen'))).
  2. If the call is legitimate in the tested path, refactor the code under test so the never-method is not relied upon to return.
  3. 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

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


AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23). Data as JSON: /api/errors/2bdf5758d26f41af. Report an issue: GitHub.