{"record":{"id":"feb1b73bd458855c","repo":"dotnet/maui","slug":"handler-is-already-being-set-elsewhere","errorCode":null,"errorMessage":"Handler is already being set elsewhere","messagePattern":"Handler is already being set elsewhere","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Controls/src/Core/Element/Element.cs","lineNumber":1082,"sourceCode":"\n\t\tprivate protected virtual void OnHandlerChangingCore(HandlerChangingEventArgs args)\n\t\t{\n\t\t\tHandlerChanging?.Invoke(this, args);\n\t\t\tOnHandlerChanging(args);\n\t\t}\n\n\t\tIElementHandler _previousHandler;\n\t\tvoid SetHandler(IElementHandler newHandler)\n\t\t{\n\t\t\tif (newHandler == _handler)\n\t\t\t\treturn;\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// If a handler is getting changed before the end of this method\n\t\t\t\t// Something is wired up incorrectly\n\t\t\t\tif (_previousHandler != null)\n\t\t\t\t\tthrow new InvalidOperationException(\"Handler is already being set elsewhere\");\n\n\t\t\t\t_previousHandler = _handler;\n\n\t\t\t\tOnHandlerChangingCore(new HandlerChangingEventArgs(_previousHandler, newHandler));\n\n\t\t\t\t_handler = newHandler;\n\n\t\t\t\t// Only call disconnect if the previous handler is still connected to this virtual view.\n\t\t\t\t// If a handler is being reused for a different VirtualView then the virtual\n\t\t\t\t// view would have already rolled \n\t\t\t\tif (_previousHandler?.VirtualView == this)\n\t\t\t\t\t_previousHandler?.DisconnectHandler();\n\n\t\t\t\tif (_handler?.VirtualView != this)\n\t\t\t\t\t_handler?.SetVirtualView(this);\n\n\t\t\t\tOnHandlerChangedCore();\n\t\t\t}","sourceCodeStart":1064,"sourceCodeEnd":1100,"githubUrl":"https://github.com/dotnet/maui/blob/f377ff1c5ee04d334d8a925f50c83a6b7afddf03/src/Controls/src/Core/Element/Element.cs#L1064-L1100","documentation":"Thrown by Element.SetHandler when _previousHandler is non-null at entry. SetHandler uses _previousHandler as a reentrancy sentinel: it is set at the start and cleared in a finally block. If it is still set on re-entry, another handler change is already in flight on the same element — meaning OnHandlerChangingCore or OnHandlerChangedCore triggered a recursive SetHandler call before the first completed.","triggerScenarios":"During OnHandlerChanging/OnHandlerChanged overrides or event handlers, code sets the Handler again (e.g., setting element.Handler = ... inside a HandlerChanged handler), causing re-entry into SetHandler while _previousHandler is non-null. Also triggered by a handler whose DisconnectHandler or SetVirtualView re-assigns the handler.","commonSituations":"Custom element overriding OnHandlerChanging and reassigning Handler in the same callback; a handler implementation whose DisconnectHandler triggers a re-connect; event handlers wired to HandlerChanged that mutate the Handler; faulty DI/handler-factory that re-assigns during setup.","solutions":["Do not set element.Handler from within OnHandlerChanging/OnHandlerChanged overrides or their event handlers.","If you need to swap handlers, defer it (Dispatcher.Dispatch or a flag) so it runs after the current SetHandler completes.","Audit custom handler DisconnectHandler/SetVirtualView implementations for code that re-enters SetHandler.","Remove HandlerChanged/HandlerChanging subscriptions that mutate the Handler."],"exampleFix":"// before\nprotected override void OnHandlerChanged()\n{\n    base.OnHandlerChanged();\n    this.Handler = CreateNewHandler(); // re-enters SetHandler -> throws\n}\n// after — defer\nprotected override void OnHandlerChanged()\n{\n    base.OnHandlerChanged();\n    Dispatcher.Dispatch(() => this.Handler = CreateNewHandler());\n}","handlingStrategy":"validation","validationCode":"// Do not reassign Handler from within OnHandlerChanging/OnHandlerChanged.\n// Use a deferred action if a reassignment is necessary.\nbool _reassignPending;\nprotected override void OnHandlerChanged()\n{\n    base.OnHandlerChanged();\n    _reassignPending = true;\n    Dispatcher.Dispatch(() => { if (_reassignPending) { _reassignPending = false; /* swap */ } });\n}","typeGuard":null,"tryCatchPattern":"try { element.Handler = newHandler; }\ncatch (InvalidOperationException ex) when (ex.Message == \"Handler is already being set elsewhere\")\n{\n    // defer the reassignment to avoid reentrancy\n    element.Dispatcher.Dispatch(() => element.Handler = newHandler);\n}","preventionTips":["Never set element.Handler from OnHandlerChanging/OnHandlerChanged overrides or their events.","Audit custom handler DisconnectHandler/SetVirtualView for re-entrant SetHandler calls.","Defer handler swaps with Dispatcher.Dispatch when triggered inside lifecycle callbacks."],"tags":["maui","handler","reentrancy","invalidoperation","lifecycle"],"backgroundTag":null,"analyzedSha":"f377ff1c5ee04d334d8a925f50c83a6b7afddf03","analyzedAt":"2026-08-13T14:26:18.069Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}