wailsapp/wails · error

binding method ID registration expects a function, got %s

Error message

binding method ID registration expects a function, got %s

What it means

RegisterBindingMethodID stores a stable numeric ID for a service method so the runtime can resolve bound calls even when binary obfuscation (e.g. garble) strips reflection-visible names. It reflects on the passed value and panics if it is not a func, since the ID is keyed on the function's code pointer.

Source

Thrown at v3/pkg/application/bindings.go:101

	isVariadic   bool // cached at registration to avoid reflect call per invocation
}

type Bindings struct {
	marshalError  func(error) []byte
	boundMethods  map[string]*BoundMethod
	boundByID     map[uint32]*BoundMethod
	methodAliases map[uint32]uint32
}

var registeredBindingMethodIDs sync.Map

// RegisterBindingMethodID registers a stable binding ID for a service method
// expression so the runtime can resolve it without relying on reflection-visible
// names (which may be obfuscated).
func RegisterBindingMethodID(method any, id uint32) {
	value := reflect.ValueOf(method)
	if value.Kind() != reflect.Func {
		panic(fmt.Sprintf("binding method ID registration expects a function, got %s", value.Kind()))
	}
	registeredBindingMethodIDs.Store(value.Pointer(), id)
}

// UnregisterBindingMethodID removes the stable binding ID for a service method.
// Intended for use in tests to restore global state after calling RegisterBindingMethodID.
func UnregisterBindingMethodID(method any) {
	value := reflect.ValueOf(method)
	if value.Kind() != reflect.Func {
		return
	}
	registeredBindingMethodIDs.Delete(value.Pointer())
}

func getRegisteredBindingMethodID(method reflect.Method) (uint32, bool) {
	id, ok := registeredBindingMethodIDs.Load(method.Func.Pointer())
	if !ok {
		return 0, false

View on GitHub (pinned to 0e754b1b40)

Solutions

  1. Pass the method value itself: app.RegisterBindingMethodID(svc.GetUsers, id)
  2. Do not pass the receiver, a string name, or a nil value
  3. Keep the argument a first-class func so value.Pointer() is a valid code address

Example fix

// before
app.RegisterBindingMethodID("GetUsers", 42)      // string: panics
app.RegisterBindingMethodID(userSvc, 42)          // struct: panics

// after
app.RegisterBindingMethodID(userSvc.GetUsers, 42) // method value: OK
Defensive patterns

Strategy: type-guard

Validate before calling

if reflect.ValueOf(method).Kind() != reflect.Func {
    return fmt.Errorf("RegisterBindingMethodID needs a method value, got %T", method)
}
app.RegisterBindingMethodID(method, id)

Type guard

func registerBindingID[F func(...any) (any, error)](app *application.App, method F, id uint32) {
    app.RegisterBindingMethodID(method, id) // non-func cannot compile
}

Prevention

When it happens

Trigger: Passing anything other than a method value / function to RegisterBindingMethodID — e.g. a struct instance, a method name string, or a nil any.

Common situations: Setting up obfuscation-resistant bindings and passing svc.SomeMethod() result incorrectly (e.g. &svc.SomeMethod, svc (the struct), or "SomeMethod" instead of the bare method value).

Related errors


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