dotnet/wpf · error · ArgumentException

SR.Cursor_InvalidStream

Error message

SR.Cursor_InvalidStream

What it means

LegacyLoadFromStream writes the stream to a temp file and loads it via LoadImage; if the resulting _cursorHandle is null or invalid, it throws ArgumentException(SR.Cursor_InvalidStream). This is the compat (quirk-flagged) stream-loading path, and the error means the stream's bytes could not be turned into a valid native cursor handle.

Solutions

  1. Seek the stream to position 0 (stream.Seek(0, SeekOrigin.Begin)) before constructing the Cursor.
  2. Verify the stream actually contains .cur/.ani bytes (check length and first bytes) rather than another resource.
  3. Confirm the embedded resource name and that it was copied into the assembly.
  4. Catch ArgumentException around Cursor construction and fall back to a built-in cursor.

Example fix

// before
using var s = assembly.GetManifestResourceStream("App.cursor.cur");
cursor = new Cursor(s);
// after
using var s = assembly.GetManifestResourceStream("App.Resources.cursor.cur");
s.Seek(0, SeekOrigin.Begin);
cursor = new Cursor(s);
Defensive patterns

Strategy: validation

Validate before calling

using var s = assembly.GetManifestResourceStream(resourcePath);
if (s == null || s.Length == 0) throw new InvalidOperationException($"Resource missing or empty: {resourcePath}");
s.Seek(0, SeekOrigin.Begin);
Cursor cursor = new Cursor(s);

Type guard

bool IsValidCursorStream(Stream s) => s != null && s.CanSeek && s.Length > 0 && s.Position == 0;

Try / catch

try { cursor = new Cursor(stream); }
catch (ArgumentException ex)
{ logger.LogWarning("Stream is not a valid cursor: {Msg}", ex.Message); cursor = Cursors.Default; }

Prevention

When it happens

Trigger: new Cursor(Stream) (via LoadFromStream → LegacyLoadFromStream, quirk flag enabled) with a stream whose content is not a valid .cur/.ani image or is empty.

Common situations: Embedding a .cur as an assembly resource and passing the wrong manifest resource stream (getting a different/empty resource); passing a stream positioned after the data (need Seek(0)); passing non-cursor image data.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Cursor.cs:249

                        }

                        // Write any remaining bytes
                        fileStream.Write(cursorData, offset: 0, count: dataSize);
                    }
                }

                // This method is called with File Write permission still asserted.
                // However, this method just reads this file into an icon.
                _cursorHandle = UnsafeNativeMethods.LoadImageCursor(IntPtr.Zero,
                                                                    filePath,
                                                                    NativeMethods.IMAGE_CURSOR,
                                                                    0, 0,
                                                                    NativeMethods.LR_DEFAULTCOLOR |
                                                                    NativeMethods.LR_LOADFROMFILE |
                                                                    (_scaleWithDpi? NativeMethods.LR_DEFAULTSIZE : 0x0000));
                if (_cursorHandle == null || _cursorHandle.IsInvalid)
                {
                     throw new ArgumentException(SR.Cursor_InvalidStream);
                }
            }
            finally
            {
                try
                {
                    File.Delete(filePath);
                }
                catch(System.IO.IOException)
                {
                    //  We may not be able to delete the file if it's being used by some other process (e.g. Anti-virus check).
                    // There's nothing we can do in that case, so just eat the exception and leave the file behind
                }
            }
        }
        //**** end of DEAD CODE ****//

        private void LoadFromStream(Stream cursorStream)

View on GitHub (pinned to 81131a70a4)