Ffile2fix
Sign in Get started

How to fix "Return value must be of type X, Y returned" in PHP

Fatal error: Uncaught TypeError: App\Repository\UserRepository::findByEmail(): Return value must be of type App\Entity\User, null returned in /var/www/html/src/Repository/UserRepository.php:42

The function declares a return type, but on this run it returned something else, often null or false from a failed lookup. PHP checks return types at runtime and throws a TypeError when they do not match.

Also appears as: TypeError: getTotal(): Return value must be of type int, string returned · Return value must be of type array, bool returned · Return value of App\Foo::bar() must be of the type array, null returned (PHP 7) · Deprecated: Return type of MyCollection::count() should either be compatible with Countable::count(): int, or the #[\ReturnTypeWillChange] attribute should be used

Common causes

  • A lookup returns null when nothing is found, but the return type is not nullable
  • A built-in function returned false on failure (file_get_contents(), json_decode(), strpos()) and it was returned directly
  • A code path with no return statement, which returns null implicitly
  • Database values returned as strings while the function promises int or float under strict_types
  • A library extended by your code changed its return type

How to fix it

  1. Read expected vs returned. The message states the declared type and the actual type. Open the function and find every return statement.
  2. Handle the failure path. When a lookup can fail, either declare ?User and let callers check for null, or throw a specific exception like UserNotFoundException.
  3. Check built-in return values. Test for false before returning results of functions such as file_get_contents() or json_decode(), or use JSON_THROW_ON_ERROR.
  4. Add the missing return. Make sure every branch, including the end of the function, returns a value of the declared type.
  5. Cast database values. PDO often returns numbers as strings; cast with (int) or (float) before returning, or set PDO::ATTR_EMULATE_PREPARES to false with mysqlnd to get native types.
  6. Fix return types on interface implementations. For the 'should be compatible' deprecation, add the matching return type (e.g. count(): int) or #[\ReturnTypeWillChange] for code that must support older PHP.

PHP 8

public function findByEmail(string $email): ?User
{
    $row = $this->db->fetchOne('SELECT * FROM users WHERE email = ?', [$email]);
    return $row ? User::fromRow($row) : null;
}

public function getTotal(): int
{
    return (int) $this->db->fetchValue('SELECT SUM(qty) FROM items');
}

How to stop it happening again

  • Decide upfront whether a function returns null or throws on failure
  • Run PHPStan or Psalm to catch mismatched returns
  • Cast values at the data access layer

Frequently asked questions

Should I return null or throw an exception?

Return null (with a ?Type) when 'not found' is normal and expected. Throw when the caller cannot reasonably continue without a value.

Why does it say null returned when I have a return statement?

Some branch reaches the end of the function without returning, or the value you return is itself null, such as a failed query result.

What does #[\ReturnTypeWillChange] do?

It silences the PHP 8.1+ deprecation for methods implementing built-in interfaces without matching return types. It is a temporary measure; adding the proper return type is the real fix.