{"record":{"id":"e95a0d6bb4b605c8","repo":"dotnet/wpf","slug":"sr-invalidoperation-cannotreenterpagefunction","errorCode":null,"errorMessage":"SR.InvalidOperation_CannotReenterPageFunction","messagePattern":"SR\\.InvalidOperation_CannotReenterPageFunction","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Navigation/NavigationService.cs","lineNumber":1632,"sourceCode":"\n            if (EventTrace.IsEnabled(EventTrace.Keyword.KeywordHosting | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info))\n            {\n                EventTrace.EventProvider.TraceEvent(\n                    EventTrace.Event.Wpf_NavigationStart, EventTrace.Keyword.KeywordHosting | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Info,\n                    navigateInfo != null ? navigateInfo.NavigationMode.ToString() : NavigationMode.New.ToString(),\n                    root != null ? root.ToString() : \"(null)\");\n            }\n\n            Invariant.Assert(IsConsistent(navigateInfo));\n\n            // Prevent re-starting the same PageFunction object before it has returned first.\n            if (navigateInfo == null) // not called internally, from NavigateToParentPage()\n            {\n                PageFunctionBase pf = root as PageFunctionBase;\n                // This won't detect the case when no Return event handler was attached, but then\n                // we don't run the risk of overwriting the ReturnEventSaver.\n                if (pf != null && (pf._Resume || pf._Saver != null))\n                    throw new InvalidOperationException(SR.InvalidOperation_CannotReenterPageFunction);\n            }\n\n            Uri source = navigateInfo?.Source;\n\n            // HandleNavigating will set the pending Uri from navigationState if available\n            // See comments in NavigateInfo class\n            if (!HandleNavigating(source, root, navigationState, null, false))\n            {\n                return false;\n            }\n\n            // root==_bp occurs in these cases:\n            //   - Navigate(object) was called with the current Content object. This is handled as fragment\n            //      navigation, scrolling content to top.\n            //   - Refresh(). We'll go through the entire navigation sequence.\n            //   - Going back/fwd to a journal entry associated with the same object. This is also handled\n            //      as fragment navigation.\n            if (object.ReferenceEquals(root, _bp) && (navigateInfo == null || navigateInfo.NavigationMode != NavigationMode.Refresh))","sourceCodeStart":1614,"sourceCodeEnd":1650,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Navigation/NavigationService.cs#L1614-L1650","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: inside Return event handler\nvoid pf_Return(object sender, ReturnEventArgs<string> e) {\n    navService.Navigate(new NextPage()); // can re-enter mid-Return\n}\n// after\nvoid pf_Return(object sender, ReturnEventArgs<string> e) {\n    Dispatcher.BeginInvoke(() => navService.Navigate(new NextPage()));\n}","handlingStrategy":"try-catch","validationCode":"var pf = root as PageFunctionBase;\nbool unsafeToNavigate = pf != null && (pf._Resume || pf._Saver != null);\nif (unsafeToNavigate) { /* defer navigation */ }","typeGuard":"bool IsInReturnCycle(object root) => root is PageFunctionBase pf && (pf._Resume || pf._Saver != null);","tryCatchPattern":"try { navService.Navigate(target); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"reenter\") || ex.Message.Contains(\"PageFunction\"))\n{ Dispatcher.BeginInvoke(() => navService.Navigate(target)); }","preventionTips":["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."],"tags":["wpf","navigation","pagefunction","reentrancy"],"backgroundTag":"invalid-state-transition","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}