SubtitleEdit/subtitleedit · error · InvalidOperationException
Failed to set clipboard data
Error message
Failed to set clipboard data
What it means
Thrown in CopyImageToClipboardWindows when SetClipboardData(CF_DIB, hGlobal) returns IntPtr.Zero after EmptyClipboard succeeded. The data was not accepted, most often because the clipboard was re-locked by another app between EmptyClipboard and SetClipboardData, or the CF_DIB payload (header/pixels) was malformed. On success ownership transfers to the clipboard; on failure the code frees hGlobal.
Source
Thrown at src/ui/Logic/ClipboardHelper.cs:275
// Open clipboard and set data
if (!OpenClipboard(IntPtr.Zero))
{
GlobalFree(hGlobal);
throw new InvalidOperationException("Failed to open clipboard");
}
try
{
if (!EmptyClipboard())
{
GlobalFree(hGlobal);
throw new InvalidOperationException("Failed to empty clipboard");
}
if (SetClipboardData(CF_DIB, hGlobal) == IntPtr.Zero)
{
GlobalFree(hGlobal);
throw new InvalidOperationException("Failed to set clipboard data");
}
// Clipboard now owns the memory
hGlobal = IntPtr.Zero;
}
finally
{
CloseClipboard();
}
}
catch (Exception ex)
{
Debug.WriteLine($"Failed to copy image to clipboard on Windows: {ex.Message}");
throw;
}
finally
{
if (hGlobal != IntPtr.Zero)View on GitHub (pinned to 17a9f07487)
Solutions
- Validate the BITMAPINFOHEADER fields (biSize == Marshal.SizeOf<BITMAPINFOHEADER>(), biCompression == BI_RGB, biSizeImage == imageSize, biPlanes == 1, biBitCount == 32).
- Confirm stride == width*4 and the bottom-up row order is correct before SetClipboardData.
- Retry the open/empty/set sequence; check Marshal.GetLastWin32Error().
- Disable clipboard managers/redirectors that may be stealing the clipboard between calls.
Example fix
// before
if (SetClipboardData(CF_DIB, hGlobal) == IntPtr.Zero) { GlobalFree(hGlobal); throw new InvalidOperationException("Failed to set clipboard data"); }
// after - assert header integrity and surface the Win32 error
if (header.biSize != (uint)headerSize || header.biCompression != BI_RGB || header.biSizeImage != (uint)imageSize)
throw new InvalidOperationException("Malformed DIB header before SetClipboardData.");
if (SetClipboardData(CF_DIB, hGlobal) == IntPtr.Zero)
{
var winErr = Marshal.GetLastWin32Error();
GlobalFree(hGlobal);
throw new InvalidOperationException($"Failed to set clipboard data (Win32 error {winErr}).");
} Defensive patterns
Strategy: validation
Validate before calling
if (header.biSize != (uint)headerSize || header.biCompression != BI_RGB || header.biSizeImage != (uint)imageSize)
throw new InvalidOperationException("Malformed DIB header before SetClipboardData.");
if (stride != width * 4) throw new InvalidOperationException("Stride mismatch."); Try / catch
if (SetClipboardData(CF_DIB, hGlobal) == IntPtr.Zero)
{
var e = Marshal.GetLastWin32Error();
GlobalFree(hGlobal);
throw new InvalidOperationException($"Failed to set clipboard data (Win32 {e}).");
} Prevention
- Validate BITMAPINFOHEADER fields and stride before SetClipboardData.
- Retry under clipboard contention between Empty and Set.
- Disable clipboard managers that steal the clipboard mid-operation.
When it happens
Trigger: Another process grabbed the clipboard between EmptyClipboard and SetClipboardData; the BITMAPINFOHEADER/pixel layout is invalid (wrong biSize, mismatched biSizeImage/stride, bad biCompression); the global block is too large or not properly locked-writable.
Common situations: Clipboard contention with RDP/clipboard managers; a malformed DIB header (e.g. wrong header size, non-BI_RGB compression); alpha-channel/stride mismatch; rare memory pressure.
Related errors
- Failed to allocate global memory
- Failed to decode bitmap
- Failed to lock global memory
- Failed to open clipboard
- Failed to empty clipboard
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/b9f3bea3d54e4fbf.
Report an issue: GitHub.