dotnet/wpf · error · InvalidOperationException
SR.InvalidOperation_CannotReenterPageFunction
Error message
SR.InvalidOperation_CannotReenterPageFunction
What it means
Thrown by NavigationService when a navigation is attempted while a PageFunction is still in an active Return cycle. The library checks whether the root element is a PageFunctionBase that is resuming (_Resume) or still holds a ReturnEventSaver (_Saver), which indicates the PageFunction's Return event has not fully completed and re-entering navigation would corrupt journal state.
Solutions
- Finish the PageFunction lifecycle first: only call OnReturn once and navigate away after the Return event handler completes.
- Move re-navigation logic out of the Return event handler (e.g. queue it via Dispatcher.BeginInvoke).
- Check that no Return event handler is attached when you intend a plain navigation to the PageFunction.
- Restructure to use a new PageFunction instance instead of re-entering the one mid-Return.
Example fix
// before: inside Return event handler
void pf_Return(object sender, ReturnEventArgs<string> e) {
navService.Navigate(new NextPage()); // can re-enter mid-Return
}
// after
void pf_Return(object sender, ReturnEventArgs<string> e) {
Dispatcher.BeginInvoke(() => navService.Navigate(new NextPage()));
} Defensive patterns
Strategy: try-catch
Validate before calling
var pf = root as PageFunctionBase;
bool unsafeToNavigate = pf != null && (pf._Resume || pf._Saver != null);
if (unsafeToNavigate) { /* defer navigation */ } Type guard
bool IsInReturnCycle(object root) => root is PageFunctionBase pf && (pf._Resume || pf._Saver != null);
Try / catch
try { navService.Navigate(target); }
catch (InvalidOperationException ex) when (ex.Message.Contains("reenter") || ex.Message.Contains("PageFunction"))
{ Dispatcher.BeginInvoke(() => navService.Navigate(target)); } Prevention
- Never navigate from inside a PageFunction Return handler; defer with Dispatcher.
- Call OnReturn exactly once per PageFunction instance.
- Use fresh PageFunction instances for repeat flows.
- Unit-test nested PageFunction chains end-to-end.
When it happens
Trigger: Calling Navigate/NavigateToParentPage with a root visual that is a PageFunctionBase whose _Resume flag is set or whose _Saver is non-null — i.e. navigating to a PageFunction again before its OnReturn/Return event has been fully processed.
Common situations: Re-navigating to a PageFunction from inside its own Return event handler; calling Navigate on a PageFunction still finishing a child PageFunction's Return; nested PageFunction flows where the parent is navigated to while the child's result is in flight.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- SR.ReturnEventHandlerMustBeOnParentPage
- SR.UiLessPageFunctionNotCallingOnReturn
- SR.WindowAlreadyClosed
- Cannot read Page properties because it is not in a tree…
- Processing is disabled while the Dispatcher is in this…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/e95a0d6bb4b605c8.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Navigation/NavigationService.cs:1632
if (EventTrace.IsEnabled(EventTrace.Keyword.KeywordHosting | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info))
{
EventTrace.EventProvider.TraceEvent(
EventTrace.Event.Wpf_NavigationStart, EventTrace.Keyword.KeywordHosting | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info,
navigateInfo != null ? navigateInfo.NavigationMode.ToString() : NavigationMode.New.ToString(),
root != null ? root.ToString() : "(null)");
}
Invariant.Assert(IsConsistent(navigateInfo));
// Prevent re-starting the same PageFunction object before it has returned first.
if (navigateInfo == null) // not called internally, from NavigateToParentPage()
{
PageFunctionBase pf = root as PageFunctionBase;
// This won't detect the case when no Return event handler was attached, but then
// we don't run the risk of overwriting the ReturnEventSaver.
if (pf != null && (pf._Resume || pf._Saver != null))
throw new InvalidOperationException(SR.InvalidOperation_CannotReenterPageFunction);
}
Uri source = navigateInfo?.Source;
// HandleNavigating will set the pending Uri from navigationState if available
// See comments in NavigateInfo class
if (!HandleNavigating(source, root, navigationState, null, false))
{
return false;
}
// root==_bp occurs in these cases:
// - Navigate(object) was called with the current Content object. This is handled as fragment
// navigation, scrolling content to top.
// - Refresh(). We'll go through the entire navigation sequence.
// - Going back/fwd to a journal entry associated with the same object. This is also handled
// as fragment navigation.
if (object.ReferenceEquals(root, _bp) && (navigateInfo == null || navigateInfo.NavigationMode != NavigationMode.Refresh))View on GitHub (pinned to 81131a70a4)