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
- Check Environment.UserInteractive before calling ShowDialog and skip/prompt differently when false.
- Replace the dialog with a non-interactive configuration path: config file, command-line argument, or settings store for the file path.
- Move the dialog into an interactive client (e.g. a UI front end) and keep the service headless, communicating via IPC.
- 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
- Check Environment.UserInteractive before any modal dialog
- Design services headless: take paths from config instead of dialogs
- Keep dialog code in interactive client applications only
- Use non-UI APIs for server-side printing
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
- " }} " element found. Expected fixed page element ( }} ).
- ' ' can only host a ' ' or a ' '. ' ' is an invalid…
- ' ' can only host a ' ' or a ' '. ' ' is an invalid…
- ' ' cannot contain the path delimiter: ' '.
- ' ' cannot start with the reserved character range…
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)