dotnet/wpf · error · InvalidOperationException

SR.FileNameMustNotBeNull

Error message

SR.FileNameMustNotBeNull

What it means

SaveFileDialog.OpenFile creates a stream for the file the user chose to save to. If CriticalItemName (the chosen filename) is null or empty — meaning the dialog never completed successfully — an InvalidOperationException is thrown instead of attempting to create a file from an invalid name.

Solutions

  1. Call ShowDialog() and proceed to OpenFile() only when it returned true
  2. Guard with !string.IsNullOrEmpty(dlg.FileName) before calling OpenFile
  3. Treat dialog cancellation as a normal flow branch, not an exception case
  4. For programmatic saves without user interaction, use File.Create/FileStream directly instead of SaveFileDialog

Example fix

// before
var dlg = new SaveFileDialog();
using var s = dlg.OpenFile();
// after
var dlg = new SaveFileDialog();
if (dlg.ShowDialog() == true)
{
    using var s = dlg.OpenFile();
}
Defensive patterns

Strategy: validation

Validate before calling

if (dlg.ShowDialog() != true || string.IsNullOrEmpty(dlg.FileName))
    return; // cancelled or invalid
using var s = dlg.OpenFile();

Type guard

bool HasSaveTarget(SaveFileDialog d) => d.ShowDialog() == true && !string.IsNullOrEmpty(d.FileName);

Try / catch

try { using var s = dlg.OpenFile(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("null"))
{
    // user cancelled; no save target
}

Prevention

When it happens

Trigger: Calling OpenFile() without calling ShowDialog or after the user cancelled the dialog; using a newly constructed SaveFileDialog that was never shown; Clearing the dialog state then calling OpenFile.

Common situations: Forgetting to check the nullable result of ShowDialog before opening the save stream; calling OpenFile in a finally/cleanup block that runs on cancellation; constructing the dialog on the fly for unit tests without showing it.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/Microsoft/Win32/SaveFileDialog.cs:72

        /// <summary>
        ///  Opens the file selected by the user with read-only permission.  
        /// </summary>
        ///  The filename used to open the file is the first element of the
        ///  FileNamesInternal array.
        /// <exception cref="System.InvalidOperationException">
        /// Thrown if there are no filenames stored in the SaveFileDialog.
        /// </exception>
        public Stream OpenFile()
        {

            // Extract the first filename from the ItemNames list.
            string filename = CriticalItemName;

            // If we got an empty or null filename, throw an exception to
            // tell the user we don't have any files to open.
            if (string.IsNullOrEmpty(filename))
            {
                throw new InvalidOperationException(SR.FileNameMustNotBeNull);
            }

            // Create a new FileStream from the file and return it.
            return new FileStream(filename, FileMode.Create, FileAccess.ReadWrite);
        }

        //
        //   We override the FileDialog implementation to set a default
        //   for FOS_FILEMUSTEXIST in addition to the other option flags
        //   defined in FileDialog.
        /// <summary>
        ///  Resets all properties to their default values.
        /// </summary>
        public override void Reset()
        {

            // it is VERY important that the base.reset() call remain here
            // and be located at the top of this function.

View on GitHub (pinned to 81131a70a4)