sebastianbergmann/phpunit · error · InvalidEventException

Event "%s" does not implement Event interface

Error message

Event "%s" does not implement Event interface

What it means

An event class passed to TypeMap::addMapping() must implement the marker interface PHPUnit\Event\Event; InvalidEventException is thrown when class_implements($eventClass) does not contain it. This keeps the dispatcher's dispatch(Event $event) type guarantee meaningful for custom events registered in the map.

Source

Thrown at src/Event/TypeMap.php:148

        if (!in_array(Subscriber::class, class_implements($subscriberInterface), true)) {
            throw new InvalidSubscriberException(
                sprintf(
                    'Subscriber "%s" does not extend Subscriber interface',
                    $subscriberInterface,
                ),
            );
        }
    }

    /**
     * @param class-string $eventClass
     *
     * @throws InvalidEventException
     */
    private function ensureEventClassImplementsEventInterface(string $eventClass): void
    {
        if (!in_array(Event::class, class_implements($eventClass), true)) {
            throw new InvalidEventException(
                sprintf(
                    'Event "%s" does not implement Event interface',
                    $eventClass,
                ),
            );
        }
    }

    /**
     * @param class-string $subscriberInterface
     *
     * @throws SubscriberTypeAlreadyRegisteredException
     */
    private function ensureSubscriberWasNotAlreadyRegistered(string $subscriberInterface): void
    {
        if (array_key_exists($subscriberInterface, $this->mapping)) {
            throw new SubscriberTypeAlreadyRegisteredException(
                sprintf(

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Add 'implements PHPUnit\Event\Event' to the event class.
  2. If the class wraps another library's event, make the wrapper implement Event and expose the wrapped object via a getter.
  3. Verify with in_array(Event::class, class_implements($eventClass), true) when in doubt.

Example fix

// before
final class OrderPlaced { public function __construct(public string $id) {} }
$typeMap->addMapping(OrderPlacedSubscriber::class, OrderPlaced::class); // throws

// after
use PHPUnit\Event\Event;

final class OrderPlaced implements Event { public function __construct(public string $id) {} }
$typeMap->addMapping(OrderPlacedSubscriber::class, OrderPlaced::class);
Defensive patterns

Strategy: validation

Validate before calling

if (!in_array(PHPUnit\Event\Event::class, class_implements($eventClass), true)) {
    throw new InvalidArgumentException($eventClass . ' must implement PHPUnit\\Event\\Event');
}

$typeMap->addMapping($subscriberInterface, $eventClass);

Type guard

function implementsEventContract(string $class): bool
{
    return in_array(PHPUnit\Event\Event::class, class_implements($class), true);
}

Prevention

When it happens

Trigger: Mapping a plain DTO or value class that has no 'implements Event'; mapping an enum or an interface instead of a concrete class; an event class whose parent implements a custom base event that itself does not extend PHPUnit\Event\Event.

Common situations: Bringing existing domain events into PHPUnit's emitter without adopting the Event contract; refactoring an event hierarchy and dropping the implements clause; wrapping third-party event objects instead of composing them.

Related errors


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