{"record":{"id":"3bb67e0c6cea768f","repo":"wailsapp/wails","slug":"failed-createmenu","errorCode":null,"errorMessage":"failed CreateMenu","messagePattern":"failed CreateMenu","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v2/internal/frontend/desktop/windows/winc/form.go","lineNumber":104,"sourceCode":"\tfm.SetText(\"Form\")\n\treturn fm\n}\n\nfunc (fm *Form) SetLayout(mng LayoutManager) {\n\tfm.layoutMng = mng\n}\n\n// UpdateLayout refresh layout.\nfunc (fm *Form) UpdateLayout() {\n\tif fm.layoutMng != nil {\n\t\tfm.layoutMng.Update()\n\t}\n}\n\nfunc (fm *Form) NewMenu() *Menu {\n\thMenu := w32.CreateMenu()\n\tif hMenu == 0 {\n\t\tpanic(\"failed CreateMenu\")\n\t}\n\tm := &Menu{hMenu: hMenu, hwnd: fm.hwnd}\n\tif !w32.SetMenu(fm.hwnd, hMenu) {\n\t\tpanic(\"failed SetMenu\")\n\t}\n\treturn m\n}\n\nfunc (fm *Form) DisableIcon() {\n\twindowInfo := getWindowInfo(fm.hwnd)\n\tframeless := windowInfo.IsPopup()\n\tif frameless {\n\t\treturn\n\t}\n\texStyle := w32.GetWindowLong(fm.hwnd, w32.GWL_EXSTYLE)\n\tw32.SetWindowLong(fm.hwnd, w32.GWL_EXSTYLE, uint32(exStyle|w32.WS_EX_DLGMODALFRAME))\n\tw32.SetWindowPos(fm.hwnd, 0, 0, 0, 0, 0,\n\t\tuint(","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/wailsapp/wails/blob/0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3/v2/internal/frontend/desktop/windows/winc/form.go#L86-L122","documentation":"Form.NewMenu calls the Win32 CreateMenu to allocate a menu bar and panics when it returns NULL. CreateMenu fails essentially only when the process is out of kernel handle-table slots or heap for menu objects — there are no caller-controllable arguments. In practice this panic indicates severe resource pressure (handle leak) or creation after window/thread teardown has begun.","triggerScenarios":"Calling form.NewMenu() repeatedly without DestroyMenu on replaced menus, leaking menu handles; calling NewMenu during process shutdown; a broader HANDLE leak (files, GDI, events) exhausting the kernel handle quota.","commonSituations":"Apps that rebuild menus dynamically (e.g. per locale switch or per window state) and never destroy the old HMENU; long-running Wails v2 utilities with unbounded handle growth.","solutions":["Create the menu once per Form and mutate it (AppendItem/Remove) instead of calling NewMenu repeatedly","Destroy replaced menus with w32.DestroyMenu(hMenu)","Track handle count (Task Manager -> Details -> Handles); if it grows unbounded, find and fix the leak — the menu is the victim"],"exampleFix":"// before\nfunc (f *MainForm) refreshMenu(items []Item) {\n    m := f.NewMenu() // new HMENU every refresh, old one leaked\n    for _, it := range items { m.AppendItem(...) }\n}\n\n// after\n// create once in setup: f.menu = f.NewMenu()\nfunc (f *MainForm) refreshMenu(items []Item) {\n    for f.menu.Count() > 0 { f.menu.Remove(0) } // mutate the existing menu\n    for _, it := range items { f.menu.AppendItem(...) }\n}","handlingStrategy":"validation","validationCode":"// Create the menu once; guard against resource exhaustion before extra menus.\nif w32.GetGuiResources(w32.GetCurrentProcess(), 1 /*GR_USEROBJECTS+handles*/) < 9000 {\n    m := form.NewMenu()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["One menu per form; mutate it instead of recreating","DestroyMenu any replaced HMENU","Track process handle counts to catch leaks"],"tags":["windows","win32-api","menu","resource-leak","winc","panic"],"backgroundTag":null,"analyzedSha":"0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3","analyzedAt":"2026-08-15T14:17:36.034Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}