wailsapp/wails · error

failed CreateMenu

Error message

failed CreateMenu

What it means

NewContextMenu calls the Win32 API CreatePopupMenu and panics when it returns a NULL handle (0). A NULL handle means Windows refused to allocate a new menu, which almost always indicates resource exhaustion (GDI/user handle leak) or that the call happened from the wrong thread/state. This is wails' win32 menu wrapper for right-click context menus on Windows.

Source

Thrown at v2/internal/frontend/desktop/windows/winc/menu.go:62

	checkable bool
	checked   bool
	isRadio   bool

	id uint16

	onClick EventManager
}

type RadioGroup struct {
	members []*MenuItem
	hwnd    w32.HWND
}

func NewContextMenu() *MenuItem {
	hMenu := w32.CreatePopupMenu()
	if hMenu == 0 {
		panic("failed CreateMenu")
	}

	item := &MenuItem{
		hMenu:    hMenu,
		hSubMenu: hMenu,
	}
	return item
}

func (m *Menu) Dispose() {
	if m.hMenu != 0 {
		w32.DestroyMenu(m.hMenu)
		m.hMenu = 0
	}
}

func (m *Menu) IsDisposed() bool {
	return m.hMenu == 0

View on GitHub (pinned to 0e754b1b40)

Solutions

  1. Build the context menu once and reuse it, updating items instead of recreating it on every popup
  2. Call Dispose() (w32.DestroyMenu) on every MenuItem created with NewContextMenu when you are done with it
  3. Check the process USER handle count in Task Manager / Process Explorer to confirm a leak
  4. If creation genuinely must be dynamic, wrap the call in a recover() and degrade gracefully

Example fix

// before
func (a *App) ShowContextMenu() {
    menu := winc.NewContextMenu() // leaked every invocation
    ...
}

// after
// create once in setup, attach via SetContextMenu, reuse; on shutdown:
// menu.Dispose()
Defensive patterns

Strategy: validation

Validate before calling

// preflight: ensure you are not leaking menus before creating more
if getUserObjectCountsyscall() > warningThreshold { // via GetGuiResources GetCurrentProcess, GR_USEROBJECTS
    disposeAndRebuildContextMenu()
}

Try / catch

defer func() {
    if r := recover(); r != nil {
        log.Error("context menu creation failed", "panic", r)
        // fall back to a previously built shared menu or skip the popup
    }
}()
menu := winc.NewContextMenu()

Prevention

When it happens

Trigger: Creating many context menus via NewContextMenu in a loop without ever calling Dispose(), so the process exhausts its USER object quota (default ~10k handles); or calling it after the window/thread teardown has begun.

Common situations: An app that builds a fresh context menu on every right-click (e.g. per-tree-node menus regenerated on each show) instead of reusing one; long-running apps on Windows whose handle count creeps up until CreatePopupMenu starts failing.

Related errors


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