sebastianbergmann/phpunit · error · UnknownEventTypeException

Unknown event type "%s"

Error message

Unknown event type "%s"

What it means

DirectDispatcher::dispatch() only delivers events whose concrete class is a value in the dispatcher's TypeMap (isKnownEventType() performs in_array($event::class, $mapping, true)). All built-in event classes are seeded by Facade::registerDefaultTypes(); a custom event class with no registered subscriber-interface mapping is rejected before any tracer or subscriber sees it. The check preserves the invariant that every dispatched event is routable.

Source

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

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

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

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

    /**
     * @throws Throwable
     * @throws UnknownEventTypeException
     */
    public function dispatch(Event $event): void
    {
        $eventClassName = $event::class;

        if (!$this->typeMap->isKnownEventType($event)) {
            throw new UnknownEventTypeException(
                sprintf(
                    'Unknown event type "%s"',
                    $eventClassName,
                ),
            );
        }

        foreach ($this->tracers as $tracer) {
            try {
                $tracer->trace($event);
                // @codeCoverageIgnoreStart
            } catch (Throwable $t) {
                $this->handleThrowable($t);
            }
            // @codeCoverageIgnoreEnd
        }

        if (!array_key_exists($eventClassName, $this->subscribers)) {

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Register the event before dispatching: $typeMap->addMapping(MyEventSubscriber::class, MyEvent::class), then dispatch MyEvent through the DirectDispatcher built with that same TypeMap.
  2. For built-in events, emit through Facade::emitter() (DispatchingEmitter) instead of calling dispatch() yourself, so the seeded TypeMap is used.
  3. Ensure registration and dispatch share one TypeMap instance; a map populated after the dispatcher is constructed still works (it is the same object), but a different map will not.

Example fix

// before
$dispatcher = new DirectDispatcher(new TypeMap); // empty map
$dispatcher->dispatch(new OrderPlaced($orderId)); // UnknownEventTypeException

// after
$typeMap = new TypeMap;
$typeMap->addMapping(OrderPlacedSubscriber::class, OrderPlaced::class);
$dispatcher = new DirectDispatcher($typeMap);
$dispatcher->dispatch(new OrderPlaced($orderId));
Defensive patterns

Strategy: validation

Validate before calling

// TypeMap exposes a public predicate; use the same instance the dispatcher was built with
if (!$typeMap->isKnownEventType($event)) {
    $typeMap->addMapping($event::class . 'Subscriber', $event::class); // or skip dispatching
}
$typeMap->dispatcher()->dispatch($event);

Try / catch

try {
    $dispatcher->dispatch($event);
} catch (PHPUnit\Event\UnknownEventTypeException $e) {
    // Event class not mapped: register the mapping or drop the custom event
}

Prevention

When it happens

Trigger: Calling $dispatcher->dispatch(new MyCustomEvent(...)) with a class implementing PHPUnit\Event\Event that was never registered via TypeMap::addMapping(); constructing DirectDispatcher with 'new TypeMap' (empty map) instead of the Facade's seeded map; emitting an event class whose mapping was dropped during a refactor.

Common situations: Adding application-specific events in a custom runner built on PHPUnit's Event component; reusing the Event subsystem outside the phpunit binary and forgetting the default map is not auto-populated there; keeping dispatch code that hardcodes event class names across a PHPUnit upgrade that renamed them.

Related errors


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