sebastianbergmann/phpunit · error · UnknownSubscriberTypeException

Subscriber "%s" does not implement any known interface - did

Error message

Subscriber "%s" does not implement any known interface - did you forget to register it?

What it means

PHPUnit's event dispatcher routes events to subscribers via a TypeMap that maps subscriber interfaces (such as PHPUnit\Event\Test\PreparedSubscriber) to event classes. registerSubscriber() rejects any subscriber object whose class_implements() list contains no interface present in that map, because the dispatcher could not decide which events to deliver to it. The built-in interfaces are pre-registered by Facade::registerDefaultTypes(), so hitting this error means your subscriber implements only the marker PHPUnit\Event\Subscriber interface (or nothing) instead of a concrete subscriber interface.

Source

Thrown at src/Event/Dispatcher/DirectDispatcher.php:55

    public function __construct(TypeMap $map)
    {
        $this->typeMap = $map;
    }

    public function registerTracer(Tracer\Tracer $tracer): void
    {
        $this->tracers[] = $tracer;
    }

    /**
     * @throws MapError
     * @throws UnknownSubscriberTypeException
     */
    public function registerSubscriber(Subscriber $subscriber): void
    {
        if (!$this->typeMap->isKnownSubscriberType($subscriber)) {
            throw new UnknownSubscriberTypeException(
                sprintf(
                    'Subscriber "%s" does not implement any known interface - did you forget to register it?',
                    $subscriber::class,
                ),
            );
        }

        $eventClassName = $this->typeMap->map($subscriber);

        if (!array_key_exists($eventClassName, $this->subscribers)) {
            $this->subscribers[$eventClassName] = [];
        }

        $this->subscribers[$eventClassName][] = $subscriber;
    }

    /**
     * @throws Throwable

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Make the subscriber class implement the built-in interface for the event you care about, e.g. final class SlowTestAlert implements PHPUnit\Event\Test\PreparedSubscriber, and implement its notify(Test\Prepared $event): void method.
  2. If you need custom events, build a TypeMap, call addMapping(MySubscriberInterface::class, MyEvent::class), and construct the DirectDispatcher with that map before registering subscribers.
  3. Run var_export(class_implements($subscriber), true) and compare the list against PHPUnit\Event\* interfaces to spot stale use statements or wrong namespaces after upgrading PHPUnit.
  4. If you only want to observe every event, register a PHPUnit\Event\Tracer\Tracer via registerTracer() instead of a Subscriber.

Example fix

// before
use PHPUnit\Event\Event;
use PHPUnit\Event\Subscriber;

final class SlowTestAlert implements Subscriber
{
    public function notify(Event $event): void { /* ... */ }
}
$facade->registerSubscriber(new SlowTestAlert);

// after
use PHPUnit\Event\Test\Prepared;
use PHPUnit\Event\Test\PreparedSubscriber;

final class SlowTestAlert implements PreparedSubscriber
{
    public function notify(Prepared $event): void { /* ... */ }
}
$facade->registerSubscriber(new SlowTestAlert);
Defensive patterns

Strategy: validation

Validate before calling

$interfaces = class_implements($subscriber);
unset($interfaces[PHPUnit\Event\Subscriber::class]);

$implementsConcreteSubscriber = (bool) array_filter(
    $interfaces,
    fn (string $i) => str_starts_with($i, 'PHPUnit\Event\') && str_ends_with($i, 'Subscriber'),
);

if (!$implementsConcreteSubscriber) {
    // registerSubscriber() would throw UnknownSubscriberTypeException: fix the class first
}

Try / catch

try {
    $facade->registerSubscriber($subscriber);
} catch (PHPUnit\Event\UnknownSubscriberTypeException $e) {
    // Log and skip, or switch to registerTracer() if all events should be observed.
    // Do not swallow silently: the subscriber will receive no events.
}

Prevention

When it happens

Trigger: Calling Facade::registerSubscriber()/registerSubscribers() from an extension's bootstrap() method, or DirectDispatcher::registerSubscriber() directly, with an object that implements only PHPUnit\Event\Subscriber; a custom subscriber interface that was never registered with TypeMap::addMapping(); a subscriber whose interface was renamed or removed during a PHPUnit major-version upgrade.

Common situations: Writing a first custom PHPUnit extension (<extensions><bootstrap> in phpunit.xml) and implementing the generic Subscriber interface instead of a specific one like Test\PreparedSubscriber or TestRunner\ExecutionFinishedSubscriber; copy-pasting extension code from an older PHPUnit tutorial where interfaces lived elsewhere; trying to register a tracer-like class as a subscriber.

Related errors


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