wailsapp/wails · error
failed SetMenu
Error message
failed SetMenu
What it means
After CreateMenu succeeds, Form.NewMenu attaches the menu to the window with SetMenu and panics when it returns FALSE. SetMenu fails when the target HWND is not a valid top-level window of the calling thread, or the window is being destroyed. Unlike the CreateMenu panic, this one is usually about the state of fm.hwnd: menu bars cannot be attached to a child control or an already-destroyed window.
Source
Thrown at v2/internal/frontend/desktop/windows/winc/form.go:108
func (fm *Form) SetLayout(mng LayoutManager) {
fm.layoutMng = mng
}
// UpdateLayout refresh layout.
func (fm *Form) UpdateLayout() {
if fm.layoutMng != nil {
fm.layoutMng.Update()
}
}
func (fm *Form) NewMenu() *Menu {
hMenu := w32.CreateMenu()
if hMenu == 0 {
panic("failed CreateMenu")
}
m := &Menu{hMenu: hMenu, hwnd: fm.hwnd}
if !w32.SetMenu(fm.hwnd, hMenu) {
panic("failed SetMenu")
}
return m
}
func (fm *Form) DisableIcon() {
windowInfo := getWindowInfo(fm.hwnd)
frameless := windowInfo.IsPopup()
if frameless {
return
}
exStyle := w32.GetWindowLong(fm.hwnd, w32.GWL_EXSTYLE)
w32.SetWindowLong(fm.hwnd, w32.GWL_EXSTYLE, uint32(exStyle|w32.WS_EX_DLGMODALFRAME))
w32.SetWindowPos(fm.hwnd, 0, 0, 0, 0, 0,
uint(
w32.SWP_FRAMECHANGED|
w32.SWP_NOMOVE|
w32.SWP_NOSIZE|
w32.SWP_NOZORDER),View on GitHub (pinned to 0e754b1b40)
Solutions
- Call NewMenu on the UI thread during form setup, before the form is shown and long before it can be closed
- Guard with w32.IsWindow(fm.Handle()) if menu creation can happen late or asynchronously
- If menus must change after close, destroy the form instead and rebuild it rather than mutating a dead HWND
Example fix
// before
go func() { f.NewMenu().Append(...) }() // races window destruction -> SetMenu FALSE -> panic
// after
func (f *MainForm) Setup() { // called on UI thread right after form init
if !w32.IsWindow(f.Handle()) { return }
m := f.NewMenu()
m.Append(...)
} Defensive patterns
Strategy: validation
Validate before calling
func attachMenuSafe(f *winc.Form) *winc.Menu {
if !w32.IsWindow(f.Handle()) { return nil } // SetMenu fails on dead HWND
return f.NewMenu()
} Prevention
- Create menus on the UI thread during setup, before the window can close
- Do not call NewMenu from goroutines
When it happens
Trigger: Calling NewMenu on a Form whose HWND was destroyed (call racing app shutdown); calling NewMenu on an object whose InitWindow failed earlier so hwnd is 0; calling from a goroutine on a window owned by another thread (SetMenu requires the window's thread).
Common situations: Menu setup dispatched asynchronously while the main window closes; forms created but never fully initialized because an earlier panic/return skipped InitWindow.
Related errors
- cannot create window for " + className
- failed CreateMenu
- SendMessage(LVM_UPDATE)
- GetSysColorBrush failed
- IconType is invalid
AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15).
Data as JSON: /api/errors/7d8c381855411937.
Report an issue: GitHub.