{"record":{"id":"4675b021e3b296aa","repo":"wailsapp/wails","slug":"event-s-is-already-registered-with-data-type-s","errorCode":null,"errorMessage":"event '%s' is already registered with data type %s","messagePattern":"event '(.+?)' is already registered with data type (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/pkg/application/events.go","lineNumber":307,"sourceCode":"var voidType = reflect.TypeFor[Void]()\n\n// RegisterEvent registers a custom event name and associated data type.\n// Events may be registered at most once.\n// Duplicate calls for the same event name trigger a panic.\n//\n// The binding generator emits typing information for all registered custom events.\n// [App.EmitEvent] and [Window.EmitEvent] check the data type for registered events.\n// Data types are matched exactly and no conversion is performed.\n//\n// It is recommended to call RegisterEvent directly,\n// with constant arguments, and only from init functions.\n// Indirect calls or instantiations are not discoverable by the binding generator.\nfunc RegisterEvent[Data any](name string) {\n\tif events.IsKnownEvent(name) {\n\t\tpanic(fmt.Errorf(\"'%s' is a known system event name\", name))\n\t}\n\tif typ, ok := registeredEvents.Load(name); ok {\n\t\tpanic(fmt.Errorf(\"event '%s' is already registered with data type %s\", name, typ))\n\t}\n\n\tregisteredEvents.Store(name, reflect.TypeFor[Data]())\n\teventRegistered(name)\n}\n\nfunc validateCustomEvent(event *CustomEvent) error {\n\tr, ok := registeredEvents.Load(event.Name)\n\tif !ok {\n\t\twarnAboutUnregisteredEvent(event.Name)\n\t\treturn nil\n\t}\n\n\ttyp := r.(reflect.Type)\n\n\tif typ == voidType {\n\t\tif event.Data == nil {\n\t\t\treturn nil","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/wailsapp/wails/blob/0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3/v3/pkg/application/events.go#L289-L325","documentation":"RegisterEvent[Data] panics when the same event name is already present in the registeredEvents store, reporting the data type it was first registered with. Events may be registered at most once because the binding generator emits a single TypeScript type per name and the data type must be unambiguous.","triggerScenarios":"Calling RegisterEvent twice for the same name — from two packages' init functions, from init plus main, or across test runs in the same process (tests that re-run init or re-register without cleanup).","commonSituations":"Test suites that call RegisterEvent per test without compensating cleanup; refactoring so two init() blocks both register the same event; registering the same name with a different data type in a second module.","solutions":["Register each event exactly once, ideally in a single init() with constant arguments as the docs recommend","In tests, guard registration with sync.OnceValue or a package-level once, or skip re-registration","If two features need similar events, give them distinct names instead of reusing one"],"exampleFix":"// before\nfunc init() { app.RegisterEvent[LoginData](\"user-login\") }\nfunc TestX(t *testing.T) { app.RegisterEvent[LoginData](\"user-login\") } // panics\n\n// after\nvar registerEvents = sync.OnceValue(func() {\n    app.RegisterEvent[LoginData](\"user-login\")\n})\nfunc init() { registerEvents() }\nfunc TestX(t *testing.T) { registerEvents() }","handlingStrategy":"validation","validationCode":"// guard double registration (mirror of the internal map check)\nvar eventOnce sync.Once\nfunc registerAppEvents() {\n    eventOnce.Do(func() { app.RegisterEvent[LoginData](\"myapp:user-login\") })\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Register each event exactly once, in one init(), with constant arguments","Use sync.OnceValue in tests that may re-run registration","Give distinct names to semantically distinct events instead of reusing one"],"tags":["events","duplicate-registration","testing","panic","v3"],"backgroundTag":null,"analyzedSha":"0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3","analyzedAt":"2026-08-15T14:17:36.034Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}