dotnet/wpf · error · InvalidOperationException

SR.WindowAlreadyClosed

Error message

SR.WindowAlreadyClosed

What it means

During PageFunction completion (HandleFinish), the service needs the journal scope to update history, but it is null because the hosting window has already closed. The library cannot finish the PageFunction's Return against a closed window, so it throws.

Solutions

  1. Ensure the hosting window stays open until the PageFunction chain finishes (handle Closing event to defer).
  2. Call OnReturn before closing the window programmatically.
  3. Check window.IsLoaded / Application state before finishing PageFunctions asynchronously.
  4. Handle the InvalidOperationException and abort the pending PageFunction flow.

Example fix

// before
void child_Return(object s, ReturnEventArgs<object> e) { window.Close(); this.OnReturn(e); }
// after
void child_Return(object s, ReturnEventArgs<object> e) { this.OnReturn(e); window.Close(); }
Defensive patterns

Strategy: try-catch

Validate before calling

if (window == null || !window.IsLoaded) { /* skip OnReturn */ }

Type guard

bool CanFinish(Window w) => w != null && w.IsLoaded && !w.IsDisposed();

Try / catch

try { pf.OnReturn(args); }
catch (InvalidOperationException ex) when (ex.Message.Contains("closed"))
{ /* window closed mid-flow: abandon PageFunction chain */ }

Prevention

When it happens

Trigger: A PageFunction calls OnReturn/finishes after its hosting Window (and JournalScope) has been closed — e.g. the user closed the window while a child PageFunction was active, and HandleFinish then runs.

Common situations: Window.Close() invoked from a child PageFunction; modal dialog closed by OS title-bar while PageFunction flow in progress; finishing PageFunctions in Application shutdown.

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/a978ff50a4cdbbcd. Report an issue: GitHub.

Appendix: source

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

                EventTrace.EventProvider.TraceEvent(
                    EventTrace.Event.Wpf_NavigationPageFunctionReturn, EventTrace.Keyword.KeywordHosting, EventTrace.Level.Info,
                    endingPF.ToString());
            }

            //
            // handle this situation gracefully -
            // this happens if someone calls Navigate() and then Finishes
            // before we have a chance to navigate.
            // Investigate what this is....
            Debug.Assert(_navigateQueueItem == null,
                    "There's a navigation pending - see kusumav for details");

            // NOTE: It is not always that endingPF==_bp. A PF may end itself when its child ends. Then
            // HandleFinish() will be called for the grandparent PF while _bp is still the child PF.

            if (JournalScope == null)
            {
                throw new InvalidOperationException(SR.WindowAlreadyClosed);
            }

            Journal journal = JournalScope.Journal;
            PageFunctionBase parentPF = null;

            int parentIndex = JournalEntryPageFunction.GetParentPageJournalIndex(this, journal, endingPF);

            if (endingPF.RemoveFromJournal)
            {
                DoRemoveFromJournal(endingPF, parentIndex);
            }

            // If the parent page is a PF, resume it and let it know the child PF returned.
            // If it's not a PF, the Return event will be raised later on - see NavigateToParentPage().
            if (parentIndex != _noParentPage)
            {
                JournalEntryPageFunction parentPfEntry = journal[parentIndex] as JournalEntryPageFunction;
                if (parentPfEntry != null)

View on GitHub (pinned to 81131a70a4)