mockery/mockery · error · InvalidArgumentException

Unknown ReflectionType: %s

Error message

Unknown ReflectionType: %s

What it means

Mockery's Reflector class turns a ReflectionType from the mocked class's method signatures into a string so the generated mock can redeclare the signature. It knows ReflectionNamedType, ReflectionUnionType and ReflectionIntersectionType; anything else falls through to 'Unknown ReflectionType: %s' (Reflector.php:264). This error therefore means your PHP engine produces a reflection type object this Mockery version was never built to understand.

Source

Thrown at library/Mockery/Reflector.php:264

            );

            $intersect = array_intersect(self::TRAVERSABLE_ARRAY, $types);
            if (self::TRAVERSABLE_ARRAY === $intersect) {
                $types = array_merge(self::ITERABLE, array_diff($types, self::TRAVERSABLE_ARRAY));
            }

            return implode(
                '|',
                array_map(
                    static function (string $type): string {
                        return strpos($type, '&') === false ? $type : sprintf('(%s)', $type);
                    },
                    $types
                )
            );
        }

        throw new InvalidArgumentException('Unknown ReflectionType: ' . get_debug_type($type));
    }

    /**
     * Get the string representation of the given type.
     *
     * @return list<array{typeHint:string,isPrimitive:bool}>
     */
    private static function getTypeInformation(ReflectionType $type, ReflectionClass $declaringClass): array
    {
        // PHP 8 union types and PHP 8.1 intersection types can be recursively processed
        if ($type instanceof ReflectionUnionType || $type instanceof ReflectionIntersectionType) {
            $types = [];

            foreach ($type->getTypes() as $innerType) {
                foreach (self::getTypeInformation($innerType, $declaringClass) as $info) {
                    if ('null' === $info['typeHint'] && $info['isPrimitive']) {
                        continue;
                    }

View on GitHub (pinned to c6401d35bc)

Solutions

  1. Update Mockery: composer update mockery/mockery — each PHP release is supported in a patch/minor release soon after.
  2. If you cannot update Mockery, pin PHP to a version your Mockery release supports (composer.json require php constraint).
  3. As a stopgap, mock an interface whose signatures avoid the new type syntax, or configure Mockery's internal-class parameter overrides if the offending signature is on an internal class.
  4. Report/patch the new ReflectionType subtype upstream — the fallthrough at Reflector.php:264 is exactly where support gets added.

Example fix

// before: PHP 8.1 intersection type + old mockery => Unknown ReflectionType
$mock = Mockery::mock(Repo::class); // Repo::find(): A&B

// after: upgrade the library that needs the newer PHP types
// composer update mockery/mockery
$mock = Mockery::mock(Repo::class);
Defensive patterns

Strategy: try-catch

Validate before calling

// Fail fast with an actionable message when the toolchain is too new for this Mockery
if (version_compare(PHP_VERSION, '8.1', '>=') && \Composer\InstalledVersions::getPrettyVersion('mockery/mockery') !== null
    && version_compare(\Composer\InstalledVersions::getPrettyVersion('mockery/mockery'), '1.5', '<')) {
    throw new RuntimeException('PHP ' . PHP_VERSION . ' types need mockery >= 1.5; run composer update mockery/mockery');
}
$mock = Mockery::mock(Repo::class);

Try / catch

try {
    $mock = Mockery::mock(Repo::class);
} catch (\InvalidArgumentException $e) {
    if (str_starts_with($e->getMessage(), 'Unknown ReflectionType:')) {
        throw new RuntimeException(
            'Mockery ' . \Mockery::VERSION . ' does not support a PHP ' . PHP_VERSION . ' type; update mockery/mockery',
            0,
            $e
        );
    }
    throw $e;
}

Prevention

When it happens

Trigger: Mocking any class/interface whose method signatures use a type construct introduced after your Mockery release — historically: PHP 8.0 union types on old Mockery, PHP 8.1 intersection types on Mockery < ~1.4.4/1.5, and by construction any future ReflectionType subtype (e.g. from a new PHP minor) on current Mockery. Fires during mock generation/shouldReceive, before any expectation runs.

Common situations: CI image or local PHP upgraded (8.0 → 8.1 → 8.x) while composer.lock kept an old mockery; a dependency introduced intersection-typed signatures; running a cutting-edge PHP RC with a released Mockery version.

Related errors


AI-assisted analysis of mockery/mockery@c6401d35bc (2026-08-21). Data as JSON: /api/errors/3e3b37102ce69c6a. Report an issue: GitHub.