AvaloniaUI/Avalonia · critical · InvalidOperationException

Application.Context.MainLooper was not expected to be null.

Error message

Application.Context.MainLooper was not expected to be null.

What it means

AndroidDispatcherImpl binds to the process main Looper to dispatch UI work. In its constructor it requires App.Context.MainLooper to be non-null. A null MainLooper means the Android Application context has no main message loop available — i.e. the host process is not a normal Android app (no UI thread loop), or the context is the wrong kind.

Source

Thrown at src/Android/Avalonia.Android/AndroidDispatcherImpl.cs:30

{
    internal sealed class AndroidDispatcherImpl : IDispatcherImplWithExplicitBackgroundProcessing,
        IDispatcherImplWithPendingInput
    {
        [ThreadStatic] private static bool? s_isUIThread;
        private readonly Looper _mainLooper;
        private readonly Handler _handler;
        private readonly Runnable _signaler;
        private readonly Runnable _timerSignaler;
        private readonly Runnable _wakeupSignaler;
        private readonly MessageQueue _queue;
        private int _signaled;
        private bool _backgroundProcessingRequested;
        

        public AndroidDispatcherImpl()
        {
            _mainLooper = App.Context.MainLooper ??
                          throw new InvalidOperationException(
                              "Application.Context.MainLooper was not expected to be null.");
            if (!CurrentThreadIsLoopThread)
                throw new InvalidOperationException("This class should be instanciated from the UI thread");
            _handler = new Handler(_mainLooper);
            _signaler = new Runnable(OnSignaled);
            _timerSignaler = new Runnable(OnTimer);
            _wakeupSignaler = new Runnable(() => { });
            _queue = Looper.MyQueue();
            Looper.MyQueue().AddIdleHandler(new IdleHandler(this));
            CanQueryPendingInput = OperatingSystem.IsAndroidVersionAtLeast(23);
        }
        
        public event Action? Timer;
        private void OnTimer() => Timer?.Invoke();

        public event Action? Signaled;
        private void OnSignaled()
        {

View on GitHub (pinned to 11c5427268)

Solutions

  1. Ensure AndroidDispatcherImpl is created on the main UI thread of a real Android app with Looper.MainLooper prepared (AvaloniaMainActivity lifecycle).
  2. If in a test/instrumentation context, prepare Looper.MainLooper before instantiating the dispatcher.
  3. Avoid initializing the Avalonia Android platform on background/service processes.
  4. Bind AvaloniaAndroid only from the main process and after Application.Context is set.

Example fix

// before
_mainLooper = App.Context.MainLooper ??
    throw new InvalidOperationException("Application.Context.MainLooper was not expected to be null.");

// after (guard with actionable guidance)
_mainLooper = App.Context.MainLooper ??
    throw new InvalidOperationException(
        "Application.Context.MainLooper is null. Initialize the Avalonia Android platform on the UI thread of the main app process (Looper.MainLooper must be prepared).");
Defensive patterns

Strategy: validation

Validate before calling

// create the dispatcher only when a main looper exists
if (App.Context.MainLooper is null) return; // not a UI-capable process

Type guard

static bool HasMainLooper() => App.Context.MainLooper is not null;

Try / catch

try { _dispatcher = new AndroidDispatcherImpl(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("MainLooper"))
{ /* not a UI process; cannot run Avalonia here */ }

Prevention

When it happens

Trigger: Constructing AndroidDispatcherImpl when Application.Context (or the bound Android platform) was initialized outside a real Android app process, or before the main Looper is prepared. Also when running in an instrumentation/test context whose MainLooper is not yet available.

Common situations: Running Avalonia.Android under a non-UI host (background service, headless test runner, instrumentation without Looper.MainLooper); binding Avalonia from a context that is not the main application; multi-process apps where the dispatcher is created on a worker process.

Related errors


AI-assisted analysis of AvaloniaUI/Avalonia@11c5427268 (2026-08-13). Data as JSON: /api/errors/c5cc5e092e17f842. Report an issue: GitHub.