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
This error is thrown by the iOS NavigationPage renderer during its initialization (OnElementChanged/setup). It checks NavPage.CurrentPage for null and throws InvalidOperationException if no root Page exists. A NavigationPage must have at least one Page on its stack before the platform renderer can build its UI — the renderer needs a concrete root view controller to push onto the UINavigationController.
Source
Thrown at src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs:222
}
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 itView on GitHub (pinned to f377ff1c5e)
Solutions
- Pass a root Page to the NavigationPage constructor: `new NavigationPage(new MyRootPage())` instead of a parameterless constructor.
- If creating NavigationPage dynamically, call `PushAsync(rootPage)` synchronously immediately after construction, before it is rendered/displayed.
- If using XAML, nest a child Page inside the NavigationPage element: `<NavigationPage> <ContentPage/> </NavigationPage>`.
- Verify the root page is non-null and not removed during the renderer's initialization lifecycle.
Example fix
// before var navPage = new NavigationPage(); MainPage = navPage; navPage.PushAsync(new MyRootPage()); // too late — renderer already threw // after MainPage = new NavigationPage(new MyRootPage());
Defensive patterns
Strategy: validation
Validate before calling
// Before assigning MainPage, verify the NavigationPage has a root page
if (navPage.CurrentPage == null)
throw new InvalidOperationException("NavigationPage must have a root Page before use.");
MainPage = navPage; Type guard
public static bool HasRootPage(NavigationPage navPage)
=> navPage?.CurrentPage != null; Prevention
- Always construct NavigationPage with a root page: new NavigationPage(rootPage).
- Add a startup assertion that MainPage (if NavigationPage) has CurrentPage != null.
- Avoid parameterless NavigationPage() constructor.
When it happens
Trigger: Occurs when a NavigationPage is constructed without a root page (e.g., `new NavigationPage()`) and then rendered on iOS without ever calling PushAsync. Also triggered if the NavigationPage's root page is removed or never set before the iOS renderer's ElementChanged fires. The check at line 222 is `if (navPage.CurrentPage == null)` inside the renderer setup that wires up PushRequested/PopRequested event handlers.
Common situations: 1) Creating `new NavigationPage()` with no argument and then setting it as the MainPage or Application.MainPage before pushing content. 2) Migrating from Xamarin.Forms where the constructor sometimes lazily pushed a page, but the timing differs in MAUI's handler architecture. 3) NavigationPage created in XAML as a bare `<NavigationPage/>` without a child page element. 4) Dynamically replacing NavigationPage content where the old root is removed before the new one is set.
Related errors
- Popped page does not appear on top of current navigation sta
- ParentingViewController parent could not be found. Please fi
- InsertPageBefore is not supported globally on iOS, please us
- PopAsync is not supported globally on iOS, please use a Navi
- PopToRootAsync is not supported globally on iOS, please use
AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13).
Data as JSON: /api/errors/06338539683762df.
Report an issue: GitHub.