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 ThrowableView on GitHub (pinned to f123cdb2a2)
Solutions
- 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.
- If you need custom events, build a TypeMap, call addMapping(MySubscriberInterface::class, MyEvent::class), and construct the DirectDispatcher with that map before registering subscribers.
- 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.
- 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
- Always implement a specific built-in subscriber interface (e.g. Test\PreparedSubscriber) rather than the bare Subscriber marker.
- After upgrading PHPUnit, re-check the use statements in extension subscriber classes against the new namespaces.
- Register custom mappings in the same TypeMap the dispatcher uses before registering any custom subscriber.
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
- Unknown event type "%s"
- Subscriber "%s" does not implement a known interface
- Subscriber "%s" does not extend Subscriber interface
- Subscriber "%s" does not exist or is not an interface
- Event class "%s" does not exist
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/881ff4c3876c6d61.
Report an issue: GitHub.