sebastianbergmann/phpunit · error · UnknownEventException
Event class "%s" does not exist
Error message
Event class "%s" does not exist
What it means
The second argument of TypeMap::addMapping() must be an existing class name; ensureEventClassExists() throws UnknownEventException when class_exists() fails (including its autoload attempt). It runs before the Event-interface check, so a missing class is reported distinctly from a class that exists but does not implement Event.
Source
Thrown at src/Event/TypeMap.php:114
if (!interface_exists($subscriberInterface)) {
throw new UnknownSubscriberException(
sprintf(
'Subscriber "%s" does not exist or is not an interface',
$subscriberInterface,
),
);
}
}
/**
* @param class-string $eventClass
*
* @throws UnknownEventException
*/
private function ensureEventClassExists(string $eventClass): void
{
if (!class_exists($eventClass)) {
throw new UnknownEventException(
sprintf(
'Event class "%s" does not exist',
$eventClass,
),
);
}
}
/**
* @param class-string $subscriberInterface
*
* @throws InvalidSubscriberException
*/
private function ensureSubscriberInterfaceExtendsInterface(string $subscriberInterface): void
{
if (!in_array(Subscriber::class, class_implements($subscriberInterface), true)) {
throw new InvalidSubscriberException(
sprintf(View on GitHub (pinned to f123cdb2a2)
Solutions
- Create the event class or fix the FQCN; prefer MyEvent::class over string literals so the IDE and PHP verify it.
- Verify with class_exists(MyEvent::class) in the same process/autoloader context if unsure.
- Run 'composer dump-autoload' (or install the missing package) and retry.
Example fix
// before $typeMap->addMapping(MySubscriberInterface::class, 'App\Event\OrderPlaced'); // literal, class in App\Events\ // after use App\Events\OrderPlaced; $typeMap->addMapping(MySubscriberInterface::class, OrderPlaced::class);
Defensive patterns
Strategy: validation
Validate before calling
if (!class_exists($eventClass)) {
throw new InvalidArgumentException($eventClass . ' does not exist; create the class or fix the FQCN');
}
$typeMap->addMapping($subscriberInterface, $eventClass); Type guard
/** @phpstan-assert class-string $name */
function assertClassExists(string $name): void
{
if (!class_exists($name)) {
throw new InvalidArgumentException("Class '{$name}' does not exist");
}
} Prevention
- Use MyEvent::class instead of string literals for event class arguments.
- Create the event class before wiring its mapping.
- Verify autoloading in the same process context when registration is dynamic.
When it happens
Trigger: addMapping(MySubscriberInterface::class, 'App\Event\ThingHappened') where ThingHappened is misspelled, not yet created, or defined in a package that is not installed; case mismatches in namespace segments on case-sensitive filesystems.
Common situations: Custom event development where the mapping is wired before the event class is written; refactors that rename event classes without updating registration code; partial vendor trees after a failed 'composer install'; stale opcache after moving files.
Related errors
- Subscriber "%s" does not exist or is not an interface
- Class or interface "%s" does not exist
- Subscriber "%s" does not implement a known interface
- Subscriber "%s" does not extend Subscriber interface
- Event "%s" does not implement Event interface
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/604f1683e013cb79.
Report an issue: GitHub.