{"record":{"id":"d4b2bee20f8fc80b","repo":"wailsapp/wails","slug":"binding-method-id-registration-expects-a-function","errorCode":null,"errorMessage":"binding method ID registration expects a function, got %s","messagePattern":"binding method ID registration expects a function, got (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/pkg/application/bindings.go","lineNumber":101,"sourceCode":"\tisVariadic   bool // cached at registration to avoid reflect call per invocation\n}\n\ntype Bindings struct {\n\tmarshalError  func(error) []byte\n\tboundMethods  map[string]*BoundMethod\n\tboundByID     map[uint32]*BoundMethod\n\tmethodAliases map[uint32]uint32\n}\n\nvar registeredBindingMethodIDs sync.Map\n\n// RegisterBindingMethodID registers a stable binding ID for a service method\n// expression so the runtime can resolve it without relying on reflection-visible\n// names (which may be obfuscated).\nfunc RegisterBindingMethodID(method any, id uint32) {\n\tvalue := reflect.ValueOf(method)\n\tif value.Kind() != reflect.Func {\n\t\tpanic(fmt.Sprintf(\"binding method ID registration expects a function, got %s\", value.Kind()))\n\t}\n\tregisteredBindingMethodIDs.Store(value.Pointer(), id)\n}\n\n// UnregisterBindingMethodID removes the stable binding ID for a service method.\n// Intended for use in tests to restore global state after calling RegisterBindingMethodID.\nfunc UnregisterBindingMethodID(method any) {\n\tvalue := reflect.ValueOf(method)\n\tif value.Kind() != reflect.Func {\n\t\treturn\n\t}\n\tregisteredBindingMethodIDs.Delete(value.Pointer())\n}\n\nfunc getRegisteredBindingMethodID(method reflect.Method) (uint32, bool) {\n\tid, ok := registeredBindingMethodIDs.Load(method.Func.Pointer())\n\tif !ok {\n\t\treturn 0, false","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/wailsapp/wails/blob/0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3/v3/pkg/application/bindings.go#L83-L119","documentation":"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.","triggerScenarios":"Passing anything other than a method value / function to RegisterBindingMethodID — e.g. a struct instance, a method name string, or a nil any.","commonSituations":"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).","solutions":["Pass the method value itself: app.RegisterBindingMethodID(svc.GetUsers, id)","Do not pass the receiver, a string name, or a nil value","Keep the argument a first-class func so value.Pointer() is a valid code address"],"exampleFix":"// before\napp.RegisterBindingMethodID(\"GetUsers\", 42)      // string: panics\napp.RegisterBindingMethodID(userSvc, 42)          // struct: panics\n\n// after\napp.RegisterBindingMethodID(userSvc.GetUsers, 42) // method value: OK","handlingStrategy":"type-guard","validationCode":"if reflect.ValueOf(method).Kind() != reflect.Func {\n    return fmt.Errorf(\"RegisterBindingMethodID needs a method value, got %T\", method)\n}\napp.RegisterBindingMethodID(method, id)","typeGuard":"func registerBindingID[F func(...any) (any, error)](app *application.App, method F, id uint32) {\n    app.RegisterBindingMethodID(method, id) // non-func cannot compile\n}","tryCatchPattern":null,"preventionTips":["Always pass the bare method value: svc.Method, not \"Method\", svc, or &svc.Method","Add a tiny typed wrapper so the compiler enforces func arguments"],"tags":["bindings","reflection","obfuscation","api-misuse","panic","v3"],"backgroundTag":null,"analyzedSha":"0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3","analyzedAt":"2026-08-15T14:17:36.034Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}