wailsapp/wails · error
CreateStreamOnHGlobal failed with E_INVALIDARG
Error message
CreateStreamOnHGlobal failed with E_INVALIDARG
What it means
The Go wrapper around the Win32 CreateStreamOnHGlobal API panicked because the call returned E_INVALIDARG. This API creates an IStream over a global-memory block (HGLOBAL); E_INVALIDARG means the arguments were rejected, almost always because hGlobal is 0, was not allocated by GlobalAlloc, or the out-pointer for the stream was invalid. The wrapper converts the HRESULT into a Go panic instead of returning an error.
Source
Thrown at v3/pkg/w32/ole32.go:83
case E_OUTOFMEMORY:
panic("CoCreateInstance failed with E_OUTOFMEMORY")
case E_UNEXPECTED:
panic("CoCreateInstance failed with E_UNEXPECTED")
}
return HRESULT(ret)
}
func CreateStreamOnHGlobal(hGlobal HGLOBAL, fDeleteOnRelease bool) *IStream {
stream := new(IStream)
ret, _, _ := procCreateStreamOnHGlobal.Call(
uintptr(hGlobal),
uintptr(BoolToBOOL(fDeleteOnRelease)),
uintptr(unsafe.Pointer(&stream)))
switch uint32(ret) {
case E_INVALIDARG:
panic("CreateStreamOnHGlobal failed with E_INVALIDARG")
case E_OUTOFMEMORY:
panic("CreateStreamOnHGlobal failed with E_OUTOFMEMORY")
case E_UNEXPECTED:
panic("CreateStreamOnHGlobal failed with E_UNEXPECTED")
}
return stream
}
func OleInitialise() {
procOleInitialize.Call()
}
func RegisterDragDrop(hwnd HWND, dropTarget *DropTarget) error {
dt := combridge.New[iDropTarget](dropTarget)
hr, _, _ := procRegisterDragDrop.Call(
hwnd,
dt.Ref(),View on GitHub (pinned to 0e754b1b40)
Solutions
- Check the HGLOBAL is non-zero immediately after GlobalAlloc and before calling CreateStreamOnHGlobal
- Ensure the buffer was allocated with GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE,...) — streams require a movable allocation, not GMEM_FIXED in some paths
- Do not GlobalFree the handle yourself when fDeleteOnRelease=true; let the stream own it
- Wrap the call in a recover() to turn the panic into an error if you cannot fully validate the handle
Example fix
// before
h := GlobalAlloc(GMEM_MOVEABLE, size)
stream := w32.CreateStreamOnHGlobal(h, true) // panics if h == 0
// after
h := GlobalAlloc(GMEM_MOVEABLE, size)
if h == 0 {
return fmt.Errorf("GlobalAlloc failed: %w", errno.ERROR_NOT_ENOUGH_MEMORY)
}
stream := w32.CreateStreamOnHGlobal(h, true) Defensive patterns
Strategy: validation
Validate before calling
if hGlobal == 0 {
return fmt.Errorf("invalid HGLOBAL (0); GlobalAlloc probably failed")
}
stream := w32.CreateStreamOnHGlobal(hGlobal, true) Try / catch
defer func() {
if r := recover(); r != nil {
return fmt.Errorf("CreateStreamOnHGlobal failed: %v", r)
}
}()
stream := w32.CreateStreamOnHGlobal(h, true) Prevention
- Always check GlobalAlloc's return before building a stream on it
- Allocate with GMEM_MOVEABLE; let fDeleteOnRelease own the free
- Never reuse an HGLOBAL after its stream was released
When it happens
Trigger: Calling w32.CreateStreamOnHGlobal with a nil/zero HGLOBAL (e.g. a failed GlobalAlloc whose error was ignored), passing a handle from a different allocator (LocalAlloc/heap), or calling after the HGLOBAL was already freed with GlobalFree.
Common situations: Clipboard (SetClipboardData) and drag-and-drop (DROPDESCRIPTION / SHDoDragDrop) helper code that builds an IStream from an HGLOBAL without checking GlobalAlloc's return; freeing the HGLOBAL before the stream is released; double-create on the same handle with fDeleteOnRelease=true.
Related errors
- CreateStreamOnHGlobal failed with E_OUTOFMEMORY
- CreateStreamOnHGlobal failed with E_UNEXPECTED
- ${await resp.text()}
- InvalidStateError
- ${await resp.text()}
AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15).
Data as JSON: /api/errors/a6ac9b261d1871f3.
Report an issue: GitHub.