{"record":{"id":"7edbc96abae812a9","repo":"wailsapp/wails","slug":"error-occurred-in-app-init","errorCode":null,"errorMessage":"Error occurred in App.Init","messagePattern":"Error occurred in App\\.Init","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v2/internal/frontend/desktop/windows/winc/app.go","lineNumber":27,"sourceCode":"import (\n\t\"runtime\"\n\t\"unsafe\"\n\n\t\"github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32\"\n)\n\nvar (\n\t// resource compilation tool assigns app.ico ID of 3\n\t// rsrc -manifest app.manifest -ico app.ico -o rsrc.syso\n\tAppIconID = 3\n)\n\nfunc init() {\n\truntime.LockOSThread()\n\n\tgAppInstance = w32.GetModuleHandle(\"\")\n\tif gAppInstance == 0 {\n\t\tpanic(\"Error occurred in App.Init\")\n\t}\n\n\t// Initialize the common controls\n\tvar initCtrls w32.INITCOMMONCONTROLSEX\n\tinitCtrls.DwSize = uint32(unsafe.Sizeof(initCtrls))\n\tinitCtrls.DwICC =\n\t\tw32.ICC_LISTVIEW_CLASSES | w32.ICC_PROGRESS_CLASS | w32.ICC_TAB_CLASSES |\n\t\t\tw32.ICC_TREEVIEW_CLASSES | w32.ICC_BAR_CLASSES\n\n\tw32.InitCommonControlsEx(&initCtrls)\n}\n\n// SetAppIcon sets resource icon ID for the apps windows.\nfunc SetAppIcon(appIconID int) {\n\tAppIconID = appIconID\n}\n\nfunc GetAppInstance() w32.HINSTANCE {","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/wailsapp/wails/blob/0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3/v2/internal/frontend/desktop/windows/winc/app.go#L9-L45","documentation":"CoCreateInstance panics with 'E_UNEXPECTED' in the w32 wrapper when the COM activation hit an unforeseeable internal error. Distinct from class-not-registered or interface-not-supported (which are returned as HRESULTs, not panicked), E_UNEXPECTED here typically means COM state on the thread is broken: COM not initialized on that thread, a prior CoUninitialize imbalance, or the apartment was torn down out from under the call.","triggerScenarios":"Calling CoCreateInstance from a goroutine whose OS thread never called CoInitializeEx (COM requires per-thread init); the initializing goroutine unlocking its OS thread so calls land on different, uninitialized threads; CoUninitialize running on the thread while activations are in flight.","commonSituations":"Go-specific: forgetting runtime.LockOSThread before using COM-heavy features, so the scheduler migrates the call onto a fresh thread without COM; shared singletons in Wails apps (taskbar progress, file dialogs) whose init ran on a different goroutine than the use site.","solutions":["runtime.LockOSThread() on any goroutine that calls CoCreateInstance, and initialize COM on that same thread first.","Centralize COM usage in one dedicated thread (actor-style channel loop) that does init once.","Check other HRESULTs are being handled first — if REGDB_E_CLASSNOTREGISTERED paths work but this fires intermittently, it is a threading issue.","Ensure CoUninitialize only runs after all activations on that thread have completed."],"exampleFix":"// before\nfunc showDialog(){\n\tgo func(){\n\t\t// OS thread not locked, COM not initialized here\n\t\tCoCreateInstance(&clsid, CLSCTX_ALL, &riid, ppv) // E_UNEXPECTED panic\n\t}()\n}\n\n// after\nfunc showDialog(){\n\tgo func(){\n\t\truntime.LockOSThread()\n\t\tdefer runtime.UnlockOSThread()\n\t\tCoInitializeEx(COINIT_APARTMENTTHREADED)\n\t\tdefer CoUninitialize()\n\t\tCoCreateInstance(&clsid, CLSCTX_ALL, &riid, ppv)\n\t}()\n}","handlingStrategy":"validation","validationCode":"func comReadyOnThisThread() bool {\n\t// COM must have been initialized on this exact OS thread;\n\t// enforce by construction: always pair LockOSThread with CoInitializeEx.\n\treturn comInitDone \n}","typeGuard":null,"tryCatchPattern":"defer func() {\n\tif r := recover(); r != nil {\n\t\tif msg, _ := r.(string); strings.Contains(msg, \"E_UNEXPECTED\") {\n\t\t\terr = fmt.Errorf(\"com activation on uninit/thread-broken thread: %v\", r)\n\t\t\treturn\n\t\t}\n\t\tpanic(r)\n\t}\n}()\nCoCreateInstance(clsid, w32.CLSCTX_ALL, riid, ppv)","preventionTips":["runtime.LockOSThread on every goroutine that touches COM, then CoInitializeEx there.","Centralize COM usage on one dedicated thread with an actor-style loop.","Run CoUninitialize only after all activations on that thread finish."],"tags":["windows","com","threading","goroutine","panic"],"backgroundTag":null,"analyzedSha":"0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3","analyzedAt":"2026-08-15T14:17:36.034Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}