wailsapp/wails · error
Error occurred in App.Init
Error message
Error occurred in App.Init
What it means
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.
Source
Thrown at v2/internal/frontend/desktop/windows/winc/app.go:27
import (
"runtime"
"unsafe"
"github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32"
)
var (
// resource compilation tool assigns app.ico ID of 3
// rsrc -manifest app.manifest -ico app.ico -o rsrc.syso
AppIconID = 3
)
func init() {
runtime.LockOSThread()
gAppInstance = w32.GetModuleHandle("")
if gAppInstance == 0 {
panic("Error occurred in App.Init")
}
// Initialize the common controls
var initCtrls w32.INITCOMMONCONTROLSEX
initCtrls.DwSize = uint32(unsafe.Sizeof(initCtrls))
initCtrls.DwICC =
w32.ICC_LISTVIEW_CLASSES | w32.ICC_PROGRESS_CLASS | w32.ICC_TAB_CLASSES |
w32.ICC_TREEVIEW_CLASSES | w32.ICC_BAR_CLASSES
w32.InitCommonControlsEx(&initCtrls)
}
// SetAppIcon sets resource icon ID for the apps windows.
func SetAppIcon(appIconID int) {
AppIconID = appIconID
}
func GetAppInstance() w32.HINSTANCE {View on GitHub (pinned to 0e754b1b40)
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.
Example fix
// before
func showDialog(){
go func(){
// OS thread not locked, COM not initialized here
CoCreateInstance(&clsid, CLSCTX_ALL, &riid, ppv) // E_UNEXPECTED panic
}()
}
// after
func showDialog(){
go func(){
runtime.LockOSThread()
defer runtime.UnlockOSThread()
CoInitializeEx(COINIT_APARTMENTTHREADED)
defer CoUninitialize()
CoCreateInstance(&clsid, CLSCTX_ALL, &riid, ppv)
}()
} Defensive patterns
Strategy: validation
Validate before calling
func comReadyOnThisThread() bool {
// COM must have been initialized on this exact OS thread;
// enforce by construction: always pair LockOSThread with CoInitializeEx.
return comInitDone
} Try / catch
defer func() {
if r := recover(); r != nil {
if msg, _ := r.(string); strings.Contains(msg, "E_UNEXPECTED") {
err = fmt.Errorf("com activation on uninit/thread-broken thread: %v", r)
return
}
panic(r)
}
}()
CoCreateInstance(clsid, w32.CLSCTX_ALL, riid, ppv) Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- element has zero size (is it hidden?): ' + target.selector
- no focused element to type into; pass a selector or click a
- target requires a selector or x/y coordinates
- no element matches selector: ' + selector
- failed to init GTK
AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15).
Data as JSON: /api/errors/7edbc96abae812a9.
Report an issue: GitHub.