dotnet/wpf · error · InvalidOperationException

SR.UiLessPageFunctionNotCallingOnReturn

Error message

SR.UiLessPageFunctionNotCallingOnReturn

What it means

When a PageFunction finishes, the parent journal entry must be a normal (non-uiless) entry. If the parent entry is marked UiLess, the parent PageFunction should already have delegated navigation to a child via OnReturn; reaching navigation with a uiless parent means it did not, so the service throws.

Solutions

  1. Ensure uiless PageFunction.Start() always ends with a call to OnReturn (or navigation to another child).
  2. Verify nested PageFunction chains delegate correctly through OnReturn.
  3. Review JournalEntryType handling; make parent entries non-uiless by giving the parent an actual UI or correct delegation.
  4. Step through HandleFinish with the journal to confirm entry types.

Example fix

// before (uiless PF start)
protected override void Start() { var child = new ChildPF(); NavigationService.Navigate(child); /* never OnReturn */ }
// after
protected override void Start() {
    var child = new ChildPF();
    child.Return += (s, e) => OnReturn(e);
    NavigationService.Navigate(child);
}
Defensive patterns

Strategy: validation

Validate before calling

// ensure uiless PageFunctions always delegate:
if (pf is PageFunctionBase p && !p.GetType().IsSubclassOf(typeof(PageFunction))) { /* verify Start() calls OnReturn */ }

Try / catch

try { navService.Navigate(parentPF, navInfo); }
catch (InvalidOperationException ex) when (ex.Message.Contains("OnReturn"))
{ /* uiless parent did not delegate: fix Start() */ }

Prevention

When it happens

Trigger: A uiless (no UI) PageFunction completes a child, but navigation proceeds to the parent while its journal entry type is UiLess — i.e. the uiless parent failed to call OnReturn and delegate to another PageFunction as required.

Common situations: Object-based PageFunctions (uiless) not calling OnReturn in their Start/flow logic; mixing uiless and visual PageFunctions incorrectly in nested flows.

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


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/556e063b60666408. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Navigation/NavigationService.cs:3866

        // Two cases:
        //     Parent is a PageFunction:  parentPF is not null.
        //     Parent is a Non PageFunction: parentPF is null,
        //                                   the valid info are parentIndex and ReturnEventArgs.
        // The kind of navigation depends on finishingChildPageFunction.RemoveFromJournal:
        //   - True: then do journal navigation to the parent page (and no journal entry created
        //      for the finishing PF)
        //   - False: do new navigation to the parent page.
        private void NavigateToParentPage(PageFunctionBase finishingChildPageFunction, PageFunctionBase parentPF, object returnEventArgs, int parentIndex)
        {
            JournalEntry parentEntry = (JournalScope.Journal)[parentIndex];


            if (parentPF != null)
            {
                // We shouldn't be navigating to a PageFunction that's UiLess at this stage.
                // By now it should have started another navigation it was delegating to a child PF.
                if (parentEntry.EntryType == JournalEntryType.UiLess)
                    throw new InvalidOperationException(SR.UiLessPageFunctionNotCallingOnReturn);

                NavigateInfo navInfo = finishingChildPageFunction.RemoveFromJournal ?
                    new NavigateInfo(parentEntry.Source, NavigationMode.Back, parentEntry) :
                    new NavigateInfo(parentEntry.Source, NavigationMode.New);
                Navigate(parentPF, navInfo);
                return;
            }

            // Handle the NonPF parent page case.
            // Passing PageFunctionReturnInfo signals that the Return event should be raised for
            // the finishing child PF.
            PageFunctionReturnInfo pfRetInfo =
                finishingChildPageFunction.RemoveFromJournal ?
                new PageFunctionReturnInfo(finishingChildPageFunction, parentEntry.Source,
                    NavigationMode.Back, parentEntry, returnEventArgs) :
                new PageFunctionReturnInfo(finishingChildPageFunction, parentEntry.Source,
                    NavigationMode.New, null, returnEventArgs);
            if (parentEntry is JournalEntryUri)

View on GitHub (pinned to 81131a70a4)