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

The provided type "%s" is an interface, and cannot be instan

Error message

The provided type "%s" is an interface, and cannot be instantiated

What it means

doctrine/instantiator creates objects without invoking their constructors. Its internal getReflectionClass() gate (src/Instantiator.php:143) requires class_exists() to return true; interfaces never satisfy that, so fromNonExistingClass() runs and detects via interface_exists() that the given name is an interface. The error means the string passed to Instantiator::instantiate() names an interface type, which can never be instantiated directly in PHP.

Source

Thrown at src/Exception/InvalidArgumentException.php:22

namespace Doctrine\Instantiator\Exception;

use InvalidArgumentException as BaseInvalidArgumentException;
use ReflectionClass;

use function interface_exists;
use function sprintf;
use function trait_exists;

/**
 * Exception for invalid arguments provided to the instantiator
 */
class InvalidArgumentException extends BaseInvalidArgumentException implements ExceptionInterface
{
    public static function fromNonExistingClass(string $className): self
    {
        if (interface_exists($className)) {
            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',

View on GitHub (pinned to cbb879d6ee)

Solutions

  1. Resolve the interface to a concrete implementing class before calling instantiate(), e.g. look up the container binding and pass FileLogger::class instead of LoggerInterface::class.
  2. If the class name comes from configuration, fix the mapping entry so it points to the concrete class.
  3. If you iterate lists of type names, filter them first: keep only names where class_exists($name) is true (interfaces and traits fail this check automatically).

Example fix

// before
$logger = (new Instantiator())->instantiate(LoggerInterface::class);
// InvalidArgumentException: The provided type "LoggerInterface" is an interface,
// and cannot be instantiated

// after: pass the concrete implementation, not the abstraction
$logger = (new Instantiator())->instantiate(FileLogger::class);
Defensive patterns

Strategy: validation

Validate before calling

use function interface_exists;

if (interface_exists($className)) {
    throw new LogicException(
        sprintf('%s is an interface: resolve a concrete implementation before instantiating.', $className)
    );
}

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

Type guard

/** @phpstan-assert-if-true !interface-string $className */
function isInstantiableClassName(string $className): bool
{
    return class_exists($className) && ! interface_exists($className, false);
}

Try / catch

use Doctrine\Instantiator\Exception\InvalidArgumentException;

try {
    $instance = $instantiator->instantiate($className);
} catch (InvalidArgumentException $e) {
    // bad input: interface/trait/missing/abstract/enum name — surface it at the config boundary
    throw new InvalidTypeConfiguration($e->getMessage(), 0, $e);
}

Prevention

When it happens

Trigger: Calling (new Instantiator())->instantiate($className) where $className is an interface FQCN, e.g. Psr\Log\LoggerInterface::class or Doctrine\Instantiator\InstantiatorInterface::class. class_exists() returns false for interfaces, control enters fromNonExistingClass(), interface_exists($className) is true, and the interface message variant is returned. Typical caller code: DI containers, fixture/proxy factories, or test libraries that feed a type map straight into instantiate().

Common situations: A service container or config file maps an identifier to an interface instead of a concrete implementation; generic factory code iterates 'all types' (classes, interfaces, traits) from reflection or a manifest and passes each to instantiate(); a variable that was supposed to hold the resolved implementation still holds the abstraction name after a refactor.

Related errors


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