dotnet/wpf · error · Win32Exception
SR.Cursor_LoadImageFailure (fileName)
Error message
SR.Cursor_LoadImageFailure (fileName)
What it means
Cursor.LoadFromFile calls the Win32 LoadImage API to load a cursor from a .cur/.ani file. When LoadImage fails with ERROR_FILE_NOT_FOUND (2) or ERROR_PATH_NOT_FOUND (3), the code throws a Win32Exception carrying that code with the 'Cursor_LoadImageFailure' message that includes the file name. This tells you the cursor file path passed to the Cursor constructor does not exist on disk.
Solutions
- Verify the cursor file exists at the exact path using File.Exists before constructing the Cursor.
- Use an absolute path or Path.Combine(AppContext.BaseDirectory, relativePath) instead of a working-directory-relative path.
- Ensure the .cur/.ani file is included in project output (set Copy to Output Directory = Copy if newer for Content/Resource files).
- Fall back to Cursors.Arrow (or another built-in cursor) when the custom file cannot be loaded.
- Catch Win32Exception around Cursor construction and surface a friendly message naming the missing file.
Example fix
// before
cursor = new Cursor("Cursors\\hand.cur");
// after
string path = Path.Combine(AppContext.BaseDirectory, "Cursors", "hand.cur");
cursor = File.Exists(path) ? new Cursor(path) : Cursors.Arrow; Defensive patterns
Strategy: validation
Validate before calling
string path = Path.Combine(AppContext.BaseDirectory, "Cursors", "hand.cur");
if (!File.Exists(path)) throw new FileNotFoundException("Cursor file missing", path);
Cursor cursor = new Cursor(path); Type guard
bool IsValidCursorFile(string path) => File.Exists(path) && new FileInfo(path).Length > 0 && string.Equals(Path.GetExtension(path), ".cur", StringComparison.OrdinalIgnoreCase);
Try / catch
try { cursor = new Cursor(cursorPath); }
catch (Win32Exception ex) when (ex.NativeErrorCode == 2 || ex.NativeErrorCode == 3)
{ logger.LogWarning("Cursor file not found: {Path}", cursorPath); cursor = Cursors.Arrow; } Prevention
- Always resolve cursor paths against AppContext.BaseDirectory, not the current working directory.
- Set 'Copy to Output Directory' on cursor content files and verify deployment artifacts.
- Check File.Exists before every custom Cursor construction.
- Log the resolved absolute path in the failure handler for diagnosis.
When it happens
Trigger: new Cursor(path) or Cursor.SetCursor with a fileName string where LoadImage returns 0 and errorCode is ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND — i.e. the file or an intermediate directory does not exist.
Common situations: Hard-coded paths like 'Cursors\hand.cur' relative to a working directory that differs at runtime; files not deployed/copied to output directory (missing 'Copy to Output Directory'); missing cursor resource files in packaged ClickOnce/MSIX apps; case or extension typos.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Win32Exception(errorCode)
- ArgumentNullException
- InvalidOperationException
- InvalidOperationException
- new System.ComponentModel.Win32Exception(win32Error)
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/179fc9446e68ced4.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Cursor.cs:186
NativeMethods.LR_LOADFROMFILE |
(_scaleWithDpi? NativeMethods.LR_DEFAULTSIZE : 0x0000));
int errorCode = Marshal.GetLastWin32Error();
if (_cursorHandle == null || _cursorHandle.IsInvalid)
{
// LoadImage returns a null handle but does not set
// the error condition when icon file is of an incorrect type (e.g., .bmp)
//
// LoadImage has a bug where it doesn't set the correct error code
// when a file is given that is not an ico file. Icon load fails
// but win32 error code is still zero (success). Thus, we need to
// special case this scenario.
//
if (errorCode != 0)
{
if ((errorCode == NativeMethods.ERROR_FILE_NOT_FOUND) || (errorCode == NativeMethods.ERROR_PATH_NOT_FOUND))
{
throw new Win32Exception(errorCode, SR.Format(SR.Cursor_LoadImageFailure, fileName));
}
else
{
throw new Win32Exception(errorCode);
}
}
else
{
throw new ArgumentException(SR.Format(SR.Cursor_LoadImageFailure, fileName));
}
}
}
//**** DEAD CODE - retained only for compat, if user sets quirk flag ****
private const int BUFFERSIZE = 4096; // the maximum size of the buffer used for loading from stream
private void LegacyLoadFromStream(Stream cursorStream)
{View on GitHub (pinned to 81131a70a4)