wailsapp/wails · error
RadioGroup.MenuID: item not found:
Error message
RadioGroup.MenuID: item not found:
What it means
RadioGroup.MenuID panics when asked for the Win32 command ID of a radio menu item that is not a member of that radio group. It is called from Win32Menu.updateRadioGroup (popupmenu_windows.go:425), which runs whenever a checked radio item is updated (UpdateMenuItem / SetChecked). The panic signals an internal bookkeeping mismatch: the item was checked before the popup menu registered its radio groups during build, or the group map was rebuilt while the item reference went stale.
Source
Thrown at v3/pkg/application/popupmenu_windows.go:43
func (r *RadioGroup) Add(id int, item *MenuItem) {
*r = append(*r, &RadioGroupMember{
ID: id,
MenuItem: item,
})
}
func (r *RadioGroup) Bounds() (int, int) {
p := *r
return p[0].ID, p[len(p)-1].ID
}
func (r *RadioGroup) MenuID(item *MenuItem) int {
for _, member := range *r {
if member.MenuItem == item {
return member.ID
}
}
panic("RadioGroup.MenuID: item not found:")
}
type Win32Menu struct {
isPopup bool
menu w32.HMENU
parentWindow *windowsWebviewWindow
parent w32.HWND
menuMapping map[int]*MenuItem
checkboxItems map[*MenuItem][]int
radioGroups map[*MenuItem][]*RadioGroup
menuData *Menu
currentMenuID int
onMenuClose func()
onMenuOpen func()
isShowing atomic.Bool // guards against concurrent TrackPopupMenuEx calls
// bitmaps tracks HBITMAP handles allocated by SetMenuIcons during
// buildMenu so they can be released when the menu is rebuilt orView on GitHub (pinned to 0e754b1b40)
Solutions
- Only SetChecked(true) on radio items after the popup/context menu has been opened at least once, or drive checked state via NewMenuItemRadio(label, true) at construction
- Re-create menu items rather than reusing stale pointers across menu rebuilds
- If it reproduces with fresh pointers and a shown menu, file a bug at wailsapp/wails with a minimal repro (popup menu + radio group)
Example fix
// before (panics if menu not yet shown / stale pointer)
myRadioItem.SetChecked(true)
// after (set initial state at construction, update only after menu is shown)
myRadioItem := application.NewMenuItemRadio("Option A", true)
// later, after the context menu has been displayed:
myRadioItem.SetChecked(true) Defensive patterns
Strategy: try-catch
Try / catch
func safeSetChecked(item *application.MenuItem, checked bool) {
defer func() {
if r := recover(); r != nil {
log.Printf("SetChecked on radio item before menu registration: %v", r)
}
}()
item.SetChecked(checked)
} Prevention
- Set initial radio state via NewMenuItemRadio(label, true) instead of post-hoc SetChecked
- Do not call SetChecked on radio items before the popup menu has been shown at least once on Windows
- Never cache MenuItem pointers across menu rebuilds; recreate items with the menu
When it happens
Trigger: On Windows, calling MenuItem.SetChecked(true) on a NewMenuItemRadio item before the containing popup/context menu has been shown (radioGroups not yet populated), or after the menu was rebuilt so the *MenuItem in the map no longer equals the item being updated (pointer identity comparison fails).
Common situations: Toggling radio items from bindings right after startup; updating radio state from a background goroutine while the context menu is being rebuilt; reusing MenuItem pointers across menu rebuilds.
Related errors
- failed CreateMenu
- DrawMenuBar failed
- invalid stream batch acknowledgement
- no element matches selector: ' + target.selector
- failed CreateMenu
AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15).
Data as JSON: /api/errors/9dbed99aa99cdda3.
Report an issue: GitHub.