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

  1. Allocate a fresh HGLOBAL for every CreateStreamOnHGlobal call; never reuse the handle after a stream with fDeleteOnRelease=true has been released
  2. Call w32.OleInitialise() on the thread (usually the main/UI thread) before OLE operations
  3. Audit the code path for a previous Release() that already consumed the memory
  4. 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

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


AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15). Data as JSON: /api/errors/58eb766b1f16aee8. Report an issue: GitHub.