{"record":{"id":"d908e9f9c7efa766","repo":"wailsapp/wails","slug":"unknown-menu-type-v","errorCode":null,"errorMessage":"Unknown menu type: %v","messagePattern":"Unknown menu type: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/pkg/application/menuitem_linux_gtk3.go","lineNumber":118,"sourceCode":"func newMenuItemImpl(item *MenuItem) *linuxMenuItem {\n\tresult := &linuxMenuItem{\n\t\tmenuItem: item,\n\t}\n\tswitch item.itemType {\n\tcase text:\n\t\tresult.native = menuItemNew(item.label, item.bitmap)\n\n\tcase checkbox:\n\t\tresult.native = menuCheckItemNew(item.label, item.bitmap)\n\t\tresult.setChecked(item.checked)\n\t\tif item.accelerator != nil {\n\t\t\tresult.setAccelerator(item.accelerator)\n\t\t}\n\tcase submenu:\n\t\tresult.native = menuItemNew(item.label, item.bitmap)\n\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"Unknown menu type: %v\", item.itemType))\n\t}\n\tresult.setDisabled(result.menuItem.disabled)\n\treturn result\n}\n\nfunc newRadioItemImpl(item *MenuItem, group GSListPointer) *linuxMenuItem {\n\tresult := &linuxMenuItem{\n\t\tmenuItem: item,\n\t\tnative:   menuRadioItemNew(group, item.label),\n\t}\n\tresult.setChecked(item.checked)\n\tresult.setDisabled(result.menuItem.disabled)\n\treturn result\n}\n\nfunc newSpeechMenu() *MenuItem {\n\tspeechMenu := NewMenu()\n\tspeechMenu.Add(\"Start Speaking\").","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/wailsapp/wails/blob/0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3/v3/pkg/application/menuitem_linux_gtk3.go#L100-L136","documentation":"This is the GTK3-legacy twin of the GTK4 factory panic: newMenuItemImpl (v3/pkg/application/menuitem_linux_gtk3.go:118, built only with -tags gtk3) handles only text, checkbox and submenu values of the menuItemType enum (menuitem.go:11-16); separator, radio and anything else fall into default: and panic. menu_linux_gtk3.go routes checkbox/radio to their own factories, so in practice a separator item or a hand-built MenuItem with a bad itemType reaching this generic factory triggers the crash.","triggerScenarios":"Building with -tags gtk3 (the legacy Linux stack retained for one v3 cycle) and adding separator items that get dispatched as normal items; constructing MenuItem values with out-of-range itemType; calling newMenuItemImpl directly without switching on item.itemType first.","commonSituations":"Apps pinned to GTK3/WebKit2GTK 4.1 during the v3 migration window (GTK4 became default per IMPLEMENTATION.md Decision 1.1); CI matrices that still build the gtk3 tag; code shared between GTK3 and GTK4 paths drifting apart.","solutions":["Ensure separator items are filtered or handled before newMenuItemImpl is called (see processMenu in menu_linux_gtk3.go) — skip separators or map them to gtk_separator_menu_item_new().","If you own the factory, add a separator case to the switch instead of letting it hit default.","Create menu items only through NewMenuItem/NewCheckMenuItem/NewRadioMenuItem/NewSeparator so itemType is always valid.","Migrate the app to the default GTK4 stack (drop -tags gtk3) — the legacy path is scheduled for removal in v3.1 and receives less testing."],"exampleFix":"// before (menuitem_linux_gtk3.go)\nswitch item.itemType {\ncase text:\n\tresult.native = menuItemNew(item.label, item.bitmap)\ncase checkbox:\n\tresult.native = menuCheckItemNew(item.label, item.bitmap)\n\t...\ncase submenu:\n\tresult.native = menuItemNew(item.label, item.bitmap)\ndefault:\n\tpanic(fmt.Sprintf(\"Unknown menu type: %v\", item.itemType))\n}\n\n// after\nswitch item.itemType {\ncase text, submenu:\n\tresult.native = menuItemNew(item.label, item.bitmap)\ncase checkbox:\n\tresult.native = menuCheckItemNew(item.label, item.bitmap)\ncase separator:\n\tresult.native = menuItemSeparatorNew()\ndefault:\n\tpanic(fmt.Sprintf(\"Unknown menu type: %v\", item.itemType))\n}","handlingStrategy":"validation","validationCode":"// Before attaching menus in a -tags gtk3 build, ensure no item\n// reaches the generic factory with an unsupported type.\n// Practical guard: build items only via public constructors and\n// verify separators are supported in your Wails version.\nif runtime.GOOS == \"linux\" && usingGtk3Build() {\n\t// skip AddSeparator() unless verified, or test on the default GTK4 stack\n}","typeGuard":"// Narrowing over menuItemType values (menuitem.go:11-16)\nfunc isGenericFactoryType(t int) bool {\n\t// GTK3 generic factory: text(0), checkbox(2), submenu(4)\n\treturn t == 0 || t == 2 || t == 4\n}","tryCatchPattern":"defer func() {\n\tif r := recover(); r != nil {\n\t\tlog.Printf(\"gtk3 menu build failed: %v\", r)\n\t}\n}()\nmenu := app.NewMenu()","preventionTips":["Migrate off -tags gtk3 to the default GTK4 stack; the legacy path is scheduled for removal in v3.1.","Create items only via NewMenuItem/NewCheckMenuItem/NewRadioMenuItem/NewSeparator.","Keep GTK3 CI builds in your matrix while you still ship the legacy tag.","Reproduce menu bugs with the same build tag you ship — GTK3 and GTK4 factories differ."],"tags":["linux","gtk3","legacy-build-tag","menus","panic"],"backgroundTag":null,"analyzedSha":"0e754b1b40ba9044c2a1460e23b7c3de20fc5cf3","analyzedAt":"2026-08-15T14:17:36.034Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}