dotnet/wpf · error · InvalidOperationException

SR.CantShowModalOnNonInteractive

Error message

SR.CantShowModalOnNonInteractive

What it means

CommonDialog.ShowDialog throws this InvalidOperationException when Environment.UserInteractive is false — i.e. the process is running in a non-interactive session such as a Windows Service or a session without a desktop. Modal dialogs require a visible, interactive desktop, so the library refuses to show them rather than hanging or failing deep inside the Win32 common dialog.

Solutions

  1. Check Environment.UserInteractive before calling ShowDialog and skip/prompt differently when false.
  2. Replace the dialog with a non-interactive configuration path: config file, command-line argument, or settings store for the file path.
  3. Move the dialog into an interactive client (e.g. a UI front end) and keep the service headless, communicating via IPC.
  4. For server-side printing, use non-UI print APIs instead of PrintDialog.

Example fix

// before
var dlg = new OpenFileDialog();
if (dlg.ShowDialog() == true) { ... } // throws in a service
// after
if (!Environment.UserInteractive)
{
    path = configuration.InputFilePath; // non-interactive source
}
else
{
    var dlg = new OpenFileDialog();
    if (dlg.ShowDialog() == true) { path = dlg.FileName; }
}
Defensive patterns

Strategy: validation

Validate before calling

if (Environment.UserInteractive) { /* safe to show dialog */ }

Type guard

static bool CanShowDialog() => Environment.UserInteractive;

Try / catch

try { dlg.ShowDialog(); }
catch (InvalidOperationException) { /* non-interactive session: fall back to config */ }

Prevention

When it happens

Trigger: Calling ShowDialog() on OpenFileDialog, SaveFileDialog, PrintDialog or any CommonDialog subclass from a Windows Service, a scheduled task in a non-interactive session, an IIS/ASP.NET worker process, or any process where Environment.UserInteractive returns false.

Common situations: A service or background worker attempting to prompt the user for a file path; moving working UI code into a service/scheduled job unchanged; CI or headless sessions running UI tests that open file dialogs; print jobs invoked server-side via PrintDialog.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/CommonDialog.cs:59

        ///  of a common dialog to their default values.
        /// </summary>
        public abstract void Reset();

        /// <summary>
        ///  This is the public method that will be called to actually show
        ///  a common dialog.  Since CommonDialog is abstract, this function
        ///  performs initialization tasks for all common dialogs and then
        ///  calls RunDialog.
        /// </summary>
        public virtual bool? ShowDialog()
        {
            CheckPermissionsToShowDialog();

            // Don't allow file dialogs to be shown if not in interactive mode
            // (for example, if we're running as a service)
            if (!Environment.UserInteractive)
            {
                throw new InvalidOperationException(SR.CantShowModalOnNonInteractive);
            }

            // Call GetActiveWindow to retrieve the window handle to the active window
            // attached to the calling thread's message queue.  We'll set the owner of
            // the common dialog to this handle.
            IntPtr hwndOwner = UnsafeNativeMethods.GetActiveWindow();

            if (hwndOwner == IntPtr.Zero)
            {
                // No active window, so we'll use the parking window as the owner, 
                // if its available.
                if (Application.Current != null)
                {
                    hwndOwner = Application.Current.ParkingHwnd;
                }
            }

            HwndWrapper tempParentHwnd = null;

View on GitHub (pinned to 81131a70a4)