{"record":{"id":"b8ee1519c0ec0e4a","repo":"wailsapp/wails","slug":"cannot-create-window-for-classname","errorCode":null,"errorMessage":"cannot create window for \" + className","messagePattern":"cannot create window for \" \\+ className","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"v2/internal/frontend/desktop/windows/winc/controlbase.go","lineNumber":72,"sourceCode":"\tonMouseHover EventManager\n\tonMouseLeave EventManager\n\n\t// Keyboard events\n\tonKeyUp EventManager\n\n\t// Paint events\n\tonPaint EventManager\n\tonSize  EventManager\n\n\tm         sync.Mutex\n\tdispatchq []func()\n}\n\n// InitControl is called by controls: edit, button, treeview, listview, and so on.\nfunc (cba *ControlBase) InitControl(className string, parent Controller, exstyle, style uint) {\n\tcba.hwnd = CreateWindow(className, parent, exstyle, style)\n\tif cba.hwnd == 0 {\n\t\tpanic(\"cannot create window for \" + className)\n\t}\n\tcba.parent = parent\n}\n\n// InitWindow is called by custom window based controls such as split, panel, etc.\nfunc (cba *ControlBase) InitWindow(className string, parent Controller, exstyle, style uint) {\n\tRegClassOnlyOnce(className)\n\tcba.hwnd = CreateWindow(className, parent, exstyle, style)\n\tif cba.hwnd == 0 {\n\t\tpanic(\"cannot create window for \" + className)\n\t}\n\tcba.parent = parent\n}\n\n// SetTheme for TreeView and ListView controls.\nfunc (cba *ControlBase) SetTheme(appName string) error {\n\tif hr := w32.SetWindowTheme(cba.hwnd, syscall.StringToUTF16Ptr(appName), nil); w32.FAILED(hr) {\n\t\treturn fmt.Errorf(\"SetWindowTheme %d\", hr)","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/wailsapp/wails/blob/0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3/v2/internal/frontend/desktop/windows/winc/controlbase.go#L54-L90","documentation":"ControlBase.InitControl creates a child window with the given Win32 class name (BUTTON, EDIT, SysListView32, ...) via CreateWindow and panics when the handle is NULL. For stock classes the class is always registered by Windows, so failure comes from the arguments/environment: an invalid parent HWND, styles that are illegal for a child, or the class not being registered (unicode/manifest issues are rare). InitControl is used by every winc control constructor, so this panic surfaces at NewButton/NewEditText/... time.","triggerScenarios":"Constructing a winc control with a parent whose HWND is 0 or already destroyed (e.g. parent Form closed before child creation goroutine ran); passing style flags that combine incompatible WS_/BS_ bits; calling control constructors from a non-main thread while the message loop is torn down; a comctl32-dependent class (e.g. SysLink) not available without InitCommonControlsEx / a v6 common-controls manifest.","commonSituations":"Goroutines that create controls after the window was destroyed at app exit; missing comctl32 v6 manifest in a hand-built exe causing newer control classes to fail; passing winc.NoParent-like zero Controller where a real parent is required.","solutions":["Create all winc controls on the main/UI thread before the owning Form is closed; never race control creation against WM_DESTROY","Verify the parent controller's Handle() is a live window (w32.IsWindow) before constructing the child","For common-controls classes, ensure InitCommonControlsEx is called and the application manifest requests comctl32 v6 (Windows then provides themed Sys* classes)","Call GetLastError via w32 after a failed CreateWindow (temporarily wrap CreateWindow) to get the exact Win32 reason (ERROR_INVALID_WINDOW_HANDLE=1400, ERROR_CANNOT_FIND_WND_CLASS=1407, ...)"],"exampleFix":"// before\ngo func() {\n    btn := winc.NewPushButton(form) // goroutine may run after form destroyed -> CreateWindow returns 0 -> panic\n}()\n\n// after\nform.Synchronize(func() { // run on the UI thread while the form is alive\n    if w32.IsWindow(form.Handle()) {\n        _ = winc.NewPushButton(form)\n    }\n})","handlingStrategy":"validation","validationCode":"func isCreatableParent(p winc.Controller) bool {\n    return p != nil && p.Handle() != 0 && w32.IsWindow(p.Handle())\n}\n\nif isCreatableParent(parent) {\n    btn := winc.NewPushButton(parent)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Create all controls synchronously on the UI thread during form setup","Never let goroutines race window destruction with control creation","Ensure a comctl32 v6 manifest and InitCommonControlsEx for common-control classes"],"tags":["windows","win32-api","window-creation","winc","panic","threading"],"backgroundTag":null,"analyzedSha":"0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3","analyzedAt":"2026-08-15T14:17:36.034Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}