dotnet/maui · error · InvalidOperationException

NavigationPage must have a root Page before being used. Eith

Error message

NavigationPage must have a root Page before being used. Either call PushAsync with a valid Page, or pass a Page to the constructor before usage.

What it means

The macOS NavigationPageRenderer.Init requires NavigationPage.CurrentPage to be non-null before wiring navigation events and the toolbar. CurrentPage is null when the NavigationPage was built without a root page and nothing was pushed before rendering (the parameterless NavigationPage() ctor leaves it null). Without a current page the renderer cannot show anything, so it throws InvalidOperationException. This is the macOS counterpart of the GTK error 104.

Source

Thrown at src/Compatibility/Core/src/MacOS/Renderers/NavigationPageRenderer.cs:204

		{
			var removed = await PopPageAsync(page, animated);
			Platform.NativeToolbarTracker.UpdateToolBar();
			return removed;
		}

		protected virtual async Task<bool> OnPush(Page page, bool animated)
		{
			var shown = await AddPage(page, animated);
			Platform.NativeToolbarTracker.UpdateToolBar();
			return shown;
		}

		void Init()
		{
			ConfigurePageRenderer();

			if (NavigationPage.CurrentPage == null)
				throw new InvalidOperationException(
					"NavigationPage must have a root Page before being used. Either call PushAsync with a valid Page, or pass a Page to the constructor before usage.");

			Platform.NativeToolbarTracker.Navigation = NavigationPage;

			NavigationPage.PushRequested += OnPushRequested;
			NavigationPage.PopRequested += OnPopRequested;
			NavigationPage.PopToRootRequested += OnPopToRootRequested;
			NavigationPage.RemovePageRequested += OnRemovedPageRequested;
			NavigationPage.InsertPageBeforeRequested += OnInsertPageBeforeRequested;
			NavigationPage.Popped += OnPopped;
			NavigationPage.PoppedToRoot += OnPoppedToRoot;

			UpdateBarBackgroundColor();
			UpdateBarBackground();
			UpdateBarTextColor();

			_events = new EventTracker(this);
			_events.LoadEvents(NativeView);

View on GitHub (pinned to f377ff1c5e)

Solutions

  1. Pass a root page to the constructor: var nav = new NavigationPage(new ContentPage()); MainPage = nav;
  2. If using the parameterless ctor, PushAsync the root before the page is rendered (before MainPage assignment).
  3. Ensure custom NavigationPage subclasses always set a root before becoming visible.

Example fix

// before
var nav = new NavigationPage();
MainPage = nav; // throws: CurrentPage null

// after
var nav = new NavigationPage(new HomePage());
MainPage = nav;
Defensive patterns

Strategy: validation

Validate before calling

var nav = new NavigationPage();
if (nav.CurrentPage == null)
    await nav.PushAsync(new ContentPage());
MainPage = nav;

Type guard

static bool HasRoot(NavigationPage np) => np.CurrentPage != null;

Prevention

When it happens

Trigger: Constructing new NavigationPage() (no root) and then rendering it (assigning to MainPage) before any PushAsync. NavigationPage.CurrentPage == null at renderer Init time.

Common situations: Parameterless NavigationPage() used with intent to push later, but rendered immediately. Refactor that moved the first PushAsync after MainPage assignment. Subclass that defers root creation.

Related errors


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