dotnet/maui · critical · 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

In NavigationRenderer.ViewDidLoad, after setting up the toolbar, the renderer checks NavPage.CurrentPage. If null, the NavigationPage has no root page - the iOS navigation controller cannot function without at least one page on its stack, and later code (line 246) iterates NavPageController.Pages and pushes them. So it throws InvalidOperationException with a clear remediation message.

Source

Thrown at src/Compatibility/Core/src/iOS/Renderers/NavigationRenderer.cs:227

		}

		public override void ViewDidLoad()
		{
			base.ViewDidLoad();

			UpdateTranslucent();

			_secondaryToolbar = new SecondaryToolbar { Frame = new RectangleF(0, 0, 320, 44) };
			View.Add(_secondaryToolbar);
			_secondaryToolbar.Hidden = true;

			FindParentFlyoutPage();

			var navPage = NavPage;
			INavigationPageController navPageController = NavPage;
			if (navPage.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.");
			}

			navPageController.PushRequested += OnPushRequested;
			navPageController.PopRequested += OnPopRequested;
			navPageController.PopToRootRequested += OnPopToRootRequested;
			navPageController.RemovePageRequested += OnRemovedPageRequested;
			navPageController.InsertPageBeforeRequested += OnInsertPageBeforeRequested;

			UpdateBarBackground();
			UpdateBarTextColor();
			UpdateHideNavigationBarSeparator();
			UpdateUseLargeTitles();

			if (OperatingSystem.IsIOSVersionAtLeast(11))
				SetNeedsUpdateOfHomeIndicatorAutoHidden();

			// If there is already stuff on the stack we need to push it

View on GitHub (pinned to f377ff1c5e)

Solutions

  1. Pass a root page to the NavigationPage constructor: new NavigationPage(new RootPage()).
  2. If constructing empty, call PushAsync(rootPage) before the page is shown.
  3. Ensure the NavigationPage is not rendered until at least one child page exists.

Example fix

// before
MainPage = new NavigationPage(); // no root page

// after
MainPage = new NavigationPage(new RootPage());
Defensive patterns

Strategy: validation

Validate before calling

// Before setting MainPage:
var nav = new NavigationPage();
if (nav.CurrentPage == null)
    nav.PushAsync(new RootPage());
MainPage = nav;
// Simplest: pass root in ctor
MainPage = new NavigationPage(new RootPage());

Prevention

When it happens

Trigger: Constructing a NavigationPage with the parameterless constructor and never pushing/adding a page before it is rendered on iOS; or pushing a null page; or removing the last page so the stack becomes empty before ViewDidLoad runs.

Common situations: new NavigationPage() with no page passed and no PushAsync before display; binding MainPage to a NavigationPage whose Children is empty initially; removing all pages from the stack while the renderer is loading.

Related errors


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