{"record":{"id":"5a427c98796e7f17","repo":"dotnet/aspnetcore","slug":"the-event-eventname-is-already-registered","errorCode":null,"errorMessage":"The event '${eventName}' is already registered.","messagePattern":"The event '(.+?)' is already registered\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Components/Web.JS/src/Rendering/Events/EventTypes.ts","lineNumber":23,"sourceCode":"  browserEventName?: string;\n  createEventArgs?: (event: Event) => unknown;\n}\n\nconst eventTypeRegistry: Map<string, EventTypeOptions> = new Map();\nconst browserEventNamesToAliases: Map<string, string[]> = new Map();\nconst createBlankEventArgsOptions: EventTypeOptions = { createEventArgs: () => ({}) };\n\nexport const eventNameAliasRegisteredCallbacks: ((aliasEventName: string, browserEventName) => void)[] = [];\n\nexport function registerCustomEventType(eventName: string, options: EventTypeOptions): void {\n  if (!options) {\n    throw new Error('The options parameter is required.');\n  }\n\n  // There can't be more than one registration for the same event name because then we wouldn't\n  // know which eventargs data to supply.\n  if (eventTypeRegistry.has(eventName)) {\n    throw new Error(`The event '${eventName}' is already registered.`);\n  }\n\n  // When aliasing a browser event, the custom event name must be different from the browser event name\n  // to avoid double-triggering (once for the browser event, once for the custom event wrapper)\n  if (options.browserEventName && eventName === options.browserEventName) {\n    throw new Error(`The custom event '${eventName}' cannot have the same name as its browserEventName '${options.browserEventName}'. Choose a different name for the custom event.`);\n  }\n\n  // If applicable, register this as an alias of the given browserEventName\n  if (options.browserEventName) {\n    const aliasGroup = browserEventNamesToAliases.get(options.browserEventName);\n    if (aliasGroup) {\n      aliasGroup.push(eventName);\n    } else {\n      browserEventNamesToAliases.set(options.browserEventName, [eventName]);\n    }\n\n    // For developer convenience, it's allowed to register the custom event type *after*","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Components/Web.JS/src/Rendering/Events/EventTypes.ts#L5-L41","documentation":"Thrown by registerCustomEventType when an event name has already been added to the eventTypeRegistry. Blazor disallows duplicate registrations because each custom event name maps to exactly one eventargs-builder; a second mapping would make it ambiguous which data to supply to the handler. The guard runs before any aliasing logic so it catches both genuine duplicates and accidental re-registration.","triggerScenarios":"Calling Blazor.registerCustomEventType('myevent', {...}) twice with the same first argument in the same JS context; loading two JS files that both register the same event; importing a library that registers a custom event after the app already registered it.","commonSituations":"A shared component library and app code both register 'copy' or 'paste'; a hot-reload / HMR cycle that re-executes the registration module without a guard; bundling two versions of a Blazor extensions package.","solutions":["Search the codebase for duplicate registerCustomEventType calls with the same event name and remove or consolidate them.","Guard the registration with a check: only register if the event is not already known (call from a module loaded once).","If two libraries legitimately need the event, pick a unique prefix per library (e.g. 'libA:myevent').","Ensure the registering script is loaded exactly once via script tags or a singleton import."],"exampleFix":"// before\nBlazor.registerCustomEventType('myevent', { createEventArgs: e => ({ value: e.detail }) });\n// loaded again elsewhere -> throws\n\n// after: idempotent guard\nif (!Blazor._customEventRegistered?.('myevent')) {\n  Blazor.registerCustomEventType('myevent', { createEventArgs: e => ({ value: e.detail }) });\n}","handlingStrategy":"validation","validationCode":"// Before registering, check if already registered.\n// Blazor exposes eventNameAliasRegisteredCallbacks; for a custom guard keep a Set.\nconst registered = (globalThis.__blazorCustomEvents ??= new Set());\nif (!registered.has(eventName)) {\n  Blazor.registerCustomEventType(eventName, options);\n  registered.add(eventName);\n}","typeGuard":"// No public API to query the registry; track locally.\nfunction isCustomEventRegistered(name: string): boolean {\n  return (globalThis.__blazorCustomEvents ?? new Set()).has(name);\n}","tryCatchPattern":"try {\n  Blazor.registerCustomEventType(name, options);\n} catch (e) {\n  if (e instanceof Error && /already registered/.test(e.message)) {\n    // benign duplicate (e.g. HMR) — ignore\n  } else { throw e; }\n}","preventionTips":["Centralize custom event registration in a single module loaded once.","Add a local Set guard so HMR/re-imports don't double-register.","Prefix event names with your library name to avoid collisions across libraries."],"tags":["blazor","events","registration","duplicate"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}