{"record":{"id":"7c4983c1183741e8","repo":"fyne-io/fyne","slug":"unhandled-obj-c-exception","errorCode":null,"errorMessage":"unhandled Obj-C exception: ","messagePattern":"unhandled Obj-C exception: ","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/driver/glfw/menu_darwin.go","lineNumber":144,"sourceCode":"}\n\nfunc createNativeMenu(w *window, menu *fyne.Menu, nextItemID int) (unsafe.Pointer, int) {\n\tnsMenu := C.createDarwinMenu(C.CString(menu.Label))\n\tfor _, item := range menu.Items {\n\t\tnsMenuItem := insertNativeMenuItem(nsMenu, item, nextItemID, -1)\n\t\tnextItemID = registerCallback(w, item, nextItemID)\n\t\tif item.ChildMenu != nil {\n\t\t\tnextItemID = addNativeSubmenu(w, nsMenuItem, item.ChildMenu, nextItemID)\n\t\t}\n\t}\n\treturn nsMenu, nextItemID\n}\n\n//export exceptionCallback\nfunc exceptionCallback(e *C.char) {\n\tmsg := C.GoString(e)\n\tif ecb == nil {\n\t\tpanic(\"unhandled Obj-C exception: \" + msg)\n\t}\n\tecb(msg)\n}\n\nfunc handleSpecialItems(w *window, menu *fyne.Menu, nextItemID int, addSeparator bool) (*fyne.Menu, int) {\n\tmenu = fyne.NewMenu(menu.Label, menu.Items...) // copy so we can manipulate\n\tfor i := 0; i < len(menu.Items); i++ {\n\t\titem := menu.Items[i]\n\t\tswitch item.Label {\n\t\tcase \"About\", \"Settings\", \"Settings…\", \"Preferences\", \"Preferences…\":\n\t\t\titems := make([]*fyne.MenuItem, 0, len(menu.Items)-1)\n\t\t\titems = append(items, menu.Items[:i]...)\n\t\t\titems = append(items, menu.Items[i+1:]...)\n\t\t\tmenu, nextItemID = handleSpecialItems(w, fyne.NewMenu(menu.Label, items...), nextItemID, false)\n\t\t\ti--\n\n\t\t\tinsertNativeMenuItem(C.darwinAppMenu(), item, nextItemID, 1)\n\t\t\tif addSeparator && item.Label != \"About\" {","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/fyne-io/fyne/blob/8860ee95c356385effa5a7be51adb11c6be9d2b6/internal/driver/glfw/menu_darwin.go#L126-L162","documentation":"On macOS, native menu construction routes Obj-C NSExceptions into the exported exceptionCallback. If an exception arrives and no Go handler is registered in ecb (setExceptionCallback - currently only fyne's own tests register one), the callback re-panics with the Obj-C message so the crash is at least descriptive. In a normal app ecb is nil, so any Obj-C exception during menu setup surfaces as this panic.","triggerScenarios":"An NSException thrown while creating/inserting native menu items on macOS (setupNativeMenu / addNativeMenu path) - for example structurally invalid menu trees (submenus on separators, inconsistent indexes) or AppKit state races during menu rebuild.","commonSituations":"Crashes shortly after startup when assigning a MainMenu with unusual structure; menu rebuilds while the app menu is being mutated; macOS/AppKit behavior changes after OS updates; deeply nested or duplicated special items (About/Preferences).","solutions":["Read the appended Obj-C exception text - it names the NSException reason; fix the menu construction it points at","Simplify the MainMenu: no ChildMenu on separators, no duplicated special labels (About/Settings/Preferences), shallow nesting","Update fyne (native menu code is patched often); on the latest release, report the exception text plus stack upstream"],"exampleFix":"// before - submenu on a separator item raises NSException in AppKit\nsep := fyne.NewMenuItemSeparator()\nsep.ChildMenu = fyne.NewMenu(\"Tools\")\nmenu := fyne.NewMenu(\"Main\", sep)\n\n// after - child menus hang off normal items\nitem := fyne.NewMenuItem(\"Tools\", nil)\nitem.ChildMenu = fyne.NewMenu(\"Tools\")\nmenu := fyne.NewMenu(\"Main\", item)","handlingStrategy":"validation","validationCode":"// Pre-flight: lint menu structure for shapes known to upset AppKit.\nfunc menuValid(m *fyne.Menu) error {\n    for _, it := range m.Items {\n        if it.IsSeparator && it.ChildMenu != nil {\n            return fmt.Errorf(\"submenu attached to separator item %q\", it.Label)\n        }\n    }\n    return nil\n}\n\nif err := menuValid(mainMenu.Items[i]); err != nil { return err }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep native menus shallow and standard; avoid exotic item structures","Never attach ChildMenu to separators; put special labels (About/Preferences) at top level once","Test menu setup on the oldest macOS version you support after every AppKit-adjacent update"],"tags":["macos","objc","native-menu","crash","cgo","go"],"backgroundTag":null,"analyzedSha":"8860ee95c356385effa5a7be51adb11c6be9d2b6","analyzedAt":"2026-08-15T22:01:51.624Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}