wailsapp/wails · error
CreateStreamOnHGlobal failed with E_UNEXPECTED
Error message
CreateStreamOnHGlobal failed with E_UNEXPECTED
What it means
CreateStreamOnHGlobal returned E_UNEXPECTED. For this API it typically indicates the underlying HGLOBAL is in a bad state (already freed, locked with the wrong flags, or the handle reused after the previous stream deleted it) or that COM is unavailable on this thread. The wrapper panics because it treats all three documented failure codes as fatal.
Source
Thrown at v3/pkg/w32/ole32.go:87
}
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(),
)
if hr != S_OK {
return syscall.Errno(hr)View on GitHub (pinned to 0e754b1b40)
Solutions
- Allocate a fresh HGLOBAL for every CreateStreamOnHGlobal call; never reuse the handle after a stream with fDeleteOnRelease=true has been released
- Call w32.OleInitialise() on the thread (usually the main/UI thread) before OLE operations
- Audit the code path for a previous Release() that already consumed the memory
- Wrap in recover() and retry the whole operation with a new allocation
Defensive patterns
Strategy: try-catch
Validate before calling
if hGlobal == 0 || !validOwnedHandle(hGlobal) {
return errors.New("stale HGLOBAL")
} Try / catch
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("CreateStreamOnHGlobal: %v (stale handle or OLE not initialized?)", r)
}
}() Prevention
- Allocate a new HGLOBAL per stream; never share across streams
- Call OleInitialise once on the UI thread before OLE work
- After Release on a stream with fDeleteOnRelease, null the handle variable
When it happens
Trigger: Calling CreateStreamOnHGlobal twice on the same HGLOBAL when the first stream was created with fDeleteOnRelease=true (first Release frees the handle); using a stale/dangling HGLOBAL; calling on a thread where OleInitialize has not been run.
Common situations: Retrying a clipboard write after a failure without reallocating the HGLOBAL; caching the HGLOBAL across operations while the stream deletes it; multi-threaded code touching OLE storage from a non-OLE-initialized goroutine.
Related errors
- CreateStreamOnHGlobal failed with E_INVALIDARG
- CreateStreamOnHGlobal failed with E_OUTOFMEMORY
- invalid stream batch acknowledgement
- no element matches selector: ' + target.selector
- failed CreateMenu
AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15).
Data as JSON: /api/errors/58eb766b1f16aee8.
Report an issue: GitHub.