{"record":{"id":"49e74bf979a10b8c","repo":"sebastianbergmann/phpunit","slug":"subscriber-type-s-already-registered","errorCode":null,"errorMessage":"Subscriber type \"%s\" already registered","messagePattern":"Subscriber type \"(.+?)\" already registered","errorType":"exception","errorClass":"SubscriberTypeAlreadyRegisteredException","httpStatus":null,"severity":"error","filePath":"src/Event/TypeMap.php","lineNumber":165,"sourceCode":"        if (!in_array(Event::class, class_implements($eventClass), true)) {\n            throw new InvalidEventException(\n                sprintf(\n                    'Event \"%s\" does not implement Event interface',\n                    $eventClass,\n                ),\n            );\n        }\n    }\n\n    /**\n     * @param class-string $subscriberInterface\n     *\n     * @throws SubscriberTypeAlreadyRegisteredException\n     */\n    private function ensureSubscriberWasNotAlreadyRegistered(string $subscriberInterface): void\n    {\n        if (array_key_exists($subscriberInterface, $this->mapping)) {\n            throw new SubscriberTypeAlreadyRegisteredException(\n                sprintf(\n                    'Subscriber type \"%s\" already registered',\n                    $subscriberInterface,\n                ),\n            );\n        }\n    }\n\n    /**\n     * @param class-string $eventClass\n     *\n     * @throws EventAlreadyAssignedException\n     */\n    private function ensureEventWasNotAlreadyAssigned(string $eventClass): void\n    {\n        if (in_array($eventClass, $this->mapping, true)) {\n            throw new EventAlreadyAssignedException(\n                sprintf(","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Event/TypeMap.php#L147-L183","documentation":"TypeMap refuses double registration: addMapping() throws SubscriberTypeAlreadyRegisteredException when the subscriber interface is already a key in the private mapping array. The map is append-only through the public API, so this usually means seeding logic ran twice or custom mappings were re-added on top of the Facade's defaults.","triggerScenarios":"Calling addMapping(MyInterface::class, ...) twice on the same TypeMap; a custom runner that merges its own mappings over a map already populated by Facade::registerDefaultTypes(); a registration loop iterating the same configuration twice.","commonSituations":"Custom bootstrap code that registers mappings once per loaded extension but is executed for multiple test suites in one process; copy-pasted registration blocks; duplicated extension entries in phpunit.xml.","solutions":["Track which interfaces you have registered (e.g. a static set keyed by interface name) and skip duplicates before calling addMapping().","Deduplicate the configuration driving the registration loop so each interface appears once.","Do not re-add built-in subscriber interfaces; Facade::registerDefaultTypes() already claims them."],"exampleFix":"// before\nforeach ($config->subscriberMappings() as $interface => $event) {\n    $typeMap->addMapping($interface, $event); // second pass throws\n}\n\n// after\n$registered = [];\nforeach ($config->subscriberMappings() as $interface => $event) {\n    if (isset($registered[$interface])) { continue; }\n    $typeMap->addMapping($interface, $event);\n    $registered[$interface] = true;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    $typeMap->addMapping($subscriberInterface, $eventClass);\n} catch (PHPUnit\\Event\\SubscriberTypeAlreadyRegisteredException $e) {\n    // Idempotent bootstrap: the interface is already mapped, nothing to do\n}","preventionTips":["Make registration code idempotent: track already-registered interface names in a set and skip them.","Deduplicate extension configuration before looping over mappings.","Never re-add built-in subscriber interfaces on top of the Facade defaults."],"tags":["phpunit","type-map","duplicate-registration","php"],"backgroundTag":"duplicate-registration","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}