wailsapp/wails · error

event '%s' is already registered with data type %s

Error message

event '%s' is already registered with data type %s

What it means

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.

Source

Thrown at v3/pkg/application/events.go:307

var voidType = reflect.TypeFor[Void]()

// RegisterEvent registers a custom event name and associated data type.
// Events may be registered at most once.
// Duplicate calls for the same event name trigger a panic.
//
// The binding generator emits typing information for all registered custom events.
// [App.EmitEvent] and [Window.EmitEvent] check the data type for registered events.
// Data types are matched exactly and no conversion is performed.
//
// It is recommended to call RegisterEvent directly,
// with constant arguments, and only from init functions.
// Indirect calls or instantiations are not discoverable by the binding generator.
func RegisterEvent[Data any](name string) {
	if events.IsKnownEvent(name) {
		panic(fmt.Errorf("'%s' is a known system event name", name))
	}
	if typ, ok := registeredEvents.Load(name); ok {
		panic(fmt.Errorf("event '%s' is already registered with data type %s", name, typ))
	}

	registeredEvents.Store(name, reflect.TypeFor[Data]())
	eventRegistered(name)
}

func validateCustomEvent(event *CustomEvent) error {
	r, ok := registeredEvents.Load(event.Name)
	if !ok {
		warnAboutUnregisteredEvent(event.Name)
		return nil
	}

	typ := r.(reflect.Type)

	if typ == voidType {
		if event.Data == nil {
			return nil

View on GitHub (pinned to 0e754b1b40)

Solutions

  1. Register each event exactly once, ideally in a single init() with constant arguments as the docs recommend
  2. In tests, guard registration with sync.OnceValue or a package-level once, or skip re-registration
  3. If two features need similar events, give them distinct names instead of reusing one

Example fix

// before
func init() { app.RegisterEvent[LoginData]("user-login") }
func TestX(t *testing.T) { app.RegisterEvent[LoginData]("user-login") } // panics

// after
var registerEvents = sync.OnceValue(func() {
    app.RegisterEvent[LoginData]("user-login")
})
func init() { registerEvents() }
func TestX(t *testing.T) { registerEvents() }
Defensive patterns

Strategy: validation

Validate before calling

// guard double registration (mirror of the internal map check)
var eventOnce sync.Once
func registerAppEvents() {
    eventOnce.Do(func() { app.RegisterEvent[LoginData]("myapp:user-login") })
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15). Data as JSON: /api/errors/4675b021e3b296aa. Report an issue: GitHub.