fyne-io/fyne · critical
Run() or ShowAndRun() must be called from main goroutine
Error message
Run() or ShowAndRun() must be called from main goroutine
What it means
The glfw desktop driver's Run() must execute on the process's main goroutine: macOS/Cocoa requires the event loop on the main thread, and gLDriver.Run enforces it with an async.IsMainGoroutine() check before doing anything. The panic is deliberate - continuing would deadlock or abort deeper inside the windowing layer.
Source
Thrown at internal/driver/glfw/driver.go:192
}
func (d *gLDriver) windowList() []fyne.Window {
return d.windows
}
func (d *gLDriver) initFailed(msg string, err error) {
fyne.LogError(msg, err)
if running.Load() {
os.Exit(1) //revive:disable-line:deep-exit
}
d.Quit()
}
func (d *gLDriver) Run() {
if !async.IsMainGoroutine() {
panic("Run() or ShowAndRun() must be called from main goroutine")
}
go d.catchTerm()
d.runGL()
// Ensure lifecycle events run to completion before the app exits
l := fyne.CurrentApp().Lifecycle().(*intapp.Lifecycle)
l.WaitForEvents()
l.DestroyEventQueue()
}
func (*gLDriver) SetDisableScreenBlanking(disable bool) {
setDisableScreenBlank(disable)
}
// NewGLDriver sets up a new Driver instance implemented using the GLFW Go library and OpenGL bindings.
func NewGLDriver() fyne.Driver {
repository.Register(fyne.URISchemeFile, intRepo.NewFileRepository())View on GitHub (pinned to 8860ee95c3)
Solutions
- Call Run()/ShowAndRun() synchronously at the end of func main() - never wrap it in 'go'
- Do slow initialization in goroutines before or beside the event loop; only the Run call itself stays on main
- In tests, use the fyne test driver instead of starting the glfw event loop
Example fix
// before
func main() {
a := app.New()
w := a.NewWindow("Hi")
go w.ShowAndRun() // panics: not the main goroutine
select {}
}
// after
func main() {
a := app.New()
w := a.NewWindow("Hi")
w.ShowAndRun() // runs on main, blocks until quit
} Defensive patterns
Strategy: validation
Prevention
- Keep Run()/ShowAndRun() as the last statement of func main() - never inside 'go'
- Grep for 'go .*ShowAndRun' and 'go .*\.Run()' when a run suddenly panics
- Push slow startup work into goroutines that finish before the event loop, not around it
- Use the fyne test driver in unit tests instead of starting glfw
When it happens
Trigger: Invoking app.Run() or window.ShowAndRun() from a non-main goroutine: 'go func() { ... w.ShowAndRun() }()', launching the UI from a server goroutine, or calling it from a callback that another library runs in its own goroutine.
Common situations: Wrapping startup in 'go' to 'not block' main; starting the GUI from an HTTP handler or gRPC server loop; refactors that moved the entry point into a helper called concurrently; some test harnesses that spawn the UI.
Related errors
- async: misuse of unbounded channel, In() was closed
- async: misuse of unbounded channel, In() was closed
- implement me
- toNativePtr() failed "%s": %s
- unhandled token type: %T %+v
AI-assisted analysis of fyne-io/fyne@8860ee95c3 (2026-08-15).
Data as JSON: /api/errors/74a415d30175ba02.
Report an issue: GitHub.