dotnet/maui · error · InvalidOperationException

Handler is already being set elsewhere

Error message

Handler is already being set elsewhere

What it means

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.

Source

Thrown at src/Controls/src/Core/Element/Element.cs:1082

		private protected virtual void OnHandlerChangingCore(HandlerChangingEventArgs args)
		{
			HandlerChanging?.Invoke(this, args);
			OnHandlerChanging(args);
		}

		IElementHandler _previousHandler;
		void SetHandler(IElementHandler newHandler)
		{
			if (newHandler == _handler)
				return;

			try
			{
				// If a handler is getting changed before the end of this method
				// Something is wired up incorrectly
				if (_previousHandler != null)
					throw new InvalidOperationException("Handler is already being set elsewhere");

				_previousHandler = _handler;

				OnHandlerChangingCore(new HandlerChangingEventArgs(_previousHandler, newHandler));

				_handler = newHandler;

				// Only call disconnect if the previous handler is still connected to this virtual view.
				// If a handler is being reused for a different VirtualView then the virtual
				// view would have already rolled 
				if (_previousHandler?.VirtualView == this)
					_previousHandler?.DisconnectHandler();

				if (_handler?.VirtualView != this)
					_handler?.SetVirtualView(this);

				OnHandlerChangedCore();
			}

View on GitHub (pinned to f377ff1c5e)

Solutions

  1. Do not set element.Handler from within OnHandlerChanging/OnHandlerChanged overrides or their event handlers.
  2. If you need to swap handlers, defer it (Dispatcher.Dispatch or a flag) so it runs after the current SetHandler completes.
  3. Audit custom handler DisconnectHandler/SetVirtualView implementations for code that re-enters SetHandler.
  4. Remove HandlerChanged/HandlerChanging subscriptions that mutate the Handler.

Example fix

// before
protected override void OnHandlerChanged()
{
    base.OnHandlerChanged();
    this.Handler = CreateNewHandler(); // re-enters SetHandler -> throws
}
// after — defer
protected override void OnHandlerChanged()
{
    base.OnHandlerChanged();
    Dispatcher.Dispatch(() => this.Handler = CreateNewHandler());
}
Defensive patterns

Strategy: validation

Validate before calling

// Do not reassign Handler from within OnHandlerChanging/OnHandlerChanged.
// Use a deferred action if a reassignment is necessary.
bool _reassignPending;
protected override void OnHandlerChanged()
{
    base.OnHandlerChanged();
    _reassignPending = true;
    Dispatcher.Dispatch(() => { if (_reassignPending) { _reassignPending = false; /* swap */ } });
}

Try / catch

try { element.Handler = newHandler; }
catch (InvalidOperationException ex) when (ex.Message == "Handler is already being set elsewhere")
{
    // defer the reassignment to avoid reentrancy
    element.Dispatcher.Dispatch(() => element.Handler = newHandler);
}

Prevention

When it happens

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

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

Related errors


AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13). Data as JSON: /api/errors/feb1b73bd458855c. Report an issue: GitHub.