wailsapp/wails · critical
failed to init GTK
Error message
failed to init GTK
What it means
CoCreateInstance panics with 'E_OUTOFMEMORY' in the w32 wrapper when the COM activation could not allocate memory. For out-of-process servers this can mean the server process could not be started due to resource limits; for in-process servers it is straightforward allocation failure. As with other COM memory failures, the arguments were acceptable and the system was simply out of resources.
Source
Thrown at v2/internal/frontend/desktop/linux/frontend.go:182
func (f *Frontend) RunMainLoop() {
C.gtk_main()
}
func (f *Frontend) WindowClose() {
f.mainWindow.Destroy()
}
func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) *Frontend {
initOnce.Do(func() {
runtime.LockOSThread()
// Set GDK_BACKEND=x11 if currently unset and XDG_SESSION_TYPE is unset, unspecified or x11 to prevent warnings
if os.Getenv("GDK_BACKEND") == "" && (os.Getenv("XDG_SESSION_TYPE") == "" || os.Getenv("XDG_SESSION_TYPE") == "unspecified" || os.Getenv("XDG_SESSION_TYPE") == "x11") {
_ = os.Setenv("GDK_BACKEND", "x11")
}
if ok := C.gtk_init_check(nil, nil); ok != 1 {
panic(errors.New("failed to init GTK"))
}
})
result := &Frontend{
frontendOptions: appoptions,
logger: myLogger,
bindings: appBindings,
dispatcher: dispatcher,
ctx: ctx,
}
result.startURL, _ = url.Parse(startURL)
result.originValidator = originvalidator.NewOriginValidator(result.startURL, appoptions.BindingsAllowedOrigins)
if _starturl, _ := ctx.Value("starturl").(*url.URL); _starturl != nil {
result.startURL = _starturl
result.originValidator = originvalidator.NewOriginValidator(result.startURL, appoptions.BindingsAllowedOrigins)
} else {
if port, _ := ctx.Value("assetserverport").(string); port != "" {View on GitHub (pinned to 0e754b1b40)
Solutions
- Reduce memory pressure before activation: drop caches, free large buffers.
- Throttle concurrent CoCreateInstance calls with a semaphore instead of unbounded parallelism.
- For local-server classes, verify the server executable can launch (permissions, desktop heap) — check Event Viewer for DCOM errors.
- Recover() and retry once after debug.FreeOSMemory() if transient pressure is expected.
Example fix
// before
for _, item := range items {
go func(){ CoCreateInstance(&clsid, CLSCTX_ALL, &riid, ppv) }() // unbounded -> OOM panic
}
// after
sem := make(chan struct{}, 4)
for _, item := range items {
sem <- struct{}{}
go func(){ defer func(){ <-sem }(); CoCreateInstance(&clsid, CLSCTX_ALL, &riid, ppv) }()
} Defensive patterns
Strategy: retry
Try / catch
func createCOMObject(clsid, riid *syscall.GUID, ppv uintptr) (err error) {
for attempt := 0; attempt < 3; attempt++ {
ok := func() bool {
defer func() {
if r := recover(); r != nil {
if msg, _ := r.(string); strings.Contains(msg, "E_OUTOFMEMORY") {
return
}
panic(r)
}
}()
CoCreateInstance(clsid, w32.CLSCTX_ALL, riid, ppv)
return true
}()
if ok {
return nil
}
debug.FreeOSMemory()
time.Sleep(time.Duration(attempt+1) * 50 * time.Millisecond)
}
return errors.New("com activation failed after retries")
} Prevention
- Throttle concurrent activations with a semaphore.
- Free large caches before COM-heavy batch operations.
- For local-server classes, check DCOM event logs for launch failures.
When it happens
Trigger: Activating a COM class while the process is at its commit limit; launching a LocalServer COM executable (e.g. an Office or shell component) on a machine with exhausted desktop heap or process slots; large numbers of simultaneous COM activations from worker goroutines.
Common situations: Batch operations that instantiate shell COM objects (thumbnails, notifications) in parallel on memory-tight machines; CI runners with low memory ceilings where local testing passed but the runner panics.
Related errors
- target requires a selector or x/y coordinates
- element has zero size (is it hidden?): ' + target.selector
- no element matches selector: ' + selector
- Invalid JSON passed to callback: ${e.message}. Message: ${in
- Callback '${callbackID}' not registered!!!
AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15).
Data as JSON: /api/errors/48ded1e541694097.
Report an issue: GitHub.