doctrine/instantiator · error · Doctrine\Instantiator\Exception\InvalidArgumentException

The provided class "%s" is abstract, and cannot be instantia

Error message

The provided class "%s" is abstract, and cannot be instantiated

What it means

Thrown by fromAbstractClass() when getReflectionClass() (src/Instantiator.php:153-154) finds the requested class is abstract. Even though the instantiator bypasses constructors via ReflectionClass::newInstanceWithoutConstructor(), PHP forbids creating instances of abstract classes, so the library refuses up front. The message names the abstract class so you can redirect the call to a concrete subclass.

Source

Thrown at src/Exception/InvalidArgumentException.php:40

            return new self(sprintf('The provided type "%s" is an interface, and cannot be instantiated', $className));
        }

        if (trait_exists($className)) {
            return new self(sprintf('The provided type "%s" is a trait, and cannot be instantiated', $className));
        }

        return new self(sprintf('The provided class "%s" does not exist', $className));
    }

    /**
     * @phpstan-param ReflectionClass<T> $reflectionClass
     *
     * @template T of object
     */
    public static function fromAbstractClass(ReflectionClass $reflectionClass): self
    {
        return new self(sprintf(
            'The provided class "%s" is abstract, and cannot be instantiated',
            $reflectionClass->getName(),
        ));
    }

    public static function fromEnum(string $className): self
    {
        return new self(sprintf(
            'The provided class "%s" is an enum, and cannot be instantiated',
            $className,
        ));
    }
}

View on GitHub (pinned to cbb879d6ee)

Solutions

  1. Instantiate a concrete subclass instead: pass UserRepository::class rather than AbstractRepository::class.
  2. If the abstract type comes from a container binding or config, fix the mapping so the concrete implementation name is resolved before calling instantiate().
  3. After a dependency upgrade, grep call sites for the newly abstract class name and update them to the concrete replacements.

Example fix

// before
$repository = $instantiator->instantiate(AbstractRepository::class);
// InvalidArgumentException: The provided class "AbstractRepository" is abstract,
// and cannot be instantiated

// after: ask for the concrete subclass
$repository = $instantiator->instantiate(UserRepository::class);
Defensive patterns

Strategy: validation

Validate before calling

$reflection = new ReflectionClass($className);

if ($reflection->isAbstract()) {
    throw new LogicException(sprintf('%s is abstract: pass a concrete subclass.', $className));
}

$object = (new Instantiator())->instantiate($className);

Type guard

function isConcreteClass(string $className): bool
{
    return class_exists($className)
        && ! (new ReflectionClass($className))->isAbstract();
}

Try / catch

use Doctrine\Instantiator\Exception\InvalidArgumentException;

try {
    $instance = $instantiator->instantiate($className);
} catch (InvalidArgumentException $e) {
    if (str_contains($e->getMessage(), 'is abstract')) {
        // resolve the abstract type to a mapped concrete implementation, then retry
        $className = $this->container->getConcreteClass($className);
        return $instantiator->instantiate($className);
    }
    throw $e;
}

Prevention

When it happens

Trigger: Calling (new Instantiator())->instantiate(AbstractController::class), AbstractRepository::class, or any abstract base FQCN. The ReflectionClass built at src/Instantiator.php:151 reports isAbstract() === true and fromAbstractClass($reflection) is thrown with the class name from $reflectionClass->getName().

Common situations: A factory or container resolves by abstract type name and forgot to map it to a concrete implementation; a base class was made abstract during a framework/library upgrade but call sites still reference it; fixture/prototype tooling receives 'base entity' names from metadata that lists parents instead of leaf classes.

Related errors


AI-assisted analysis of doctrine/instantiator@cbb879d6ee (2026-08-21). Data as JSON: /api/errors/07273f65f38140e8. Report an issue: GitHub.