#3192
macOS: intermittent NSRangeException from _NSTouchBarFinderObservation removing a nextResponder observer
An application built on gpui-kit intermittently aborts on macOS with an uncaught AppKit exception raised by the Touch Bar finder. No application frames are involved: the throw happens inside AppKit during a display-cycle flush on the main run loop.
Environment
- gpui-kit git revision
86f9c0fb5907549d9a5b0aff53b4b6865933a8e8(GPUIgpui-pre =0.3.6) - MacBookPro17,1 (M1, with Touch Bar), macOS 26.6.2
- Window opened with
gpui_kit::open_windowandTitleBar::window_options(), aTitleBarin the view, default key bindings and an app menu
Exception
*** Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer <_NSTouchBarFinderObservation 0x…> for the key path "nextResponder" from <NSView 0x…> because it is not registered as an observer.'Top of the exception backtrace:
Foundation -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:]
Foundation -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:]
Foundation -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:context:]
AppKit -[_NSTouchBarFinderObservation invalidate]
AppKit ___NSTouchBarFinderSetNeedsUpdateOnMain_block_invoke_2
AppKit NSDisplayCycleObserverInvoke
AppKit NSDisplayCycleFlush
QuartzCore CA::Transaction::run_commit_handlers(CATransactionPhase)
QuartzCore CA::Transaction::commit()
...
AppKit -[NSApplication run]
<app> gpui_macos::platform::MacPlatform::runReproduction
Rare and timing dependent. It occurred:
- once during normal use of the app, about four minutes after launch, while focus was moving between two instances of the same app;
- once in a single instance while programmatically switching the frontmost app between it and Finder (Accessibility
AXFrontmost), within the first 25 switches.
A further ~320 switches did not reproduce it, neither in the app nor in a minimal gpui_kit::open_window window, so I cannot yet say whether anything specific to the app raises the rate.
Possibly related
- feigeCode/navop#268 — a GPUI app hitting the same
_NSTouchBarFinderObservationexception on an Intel Touch Bar Mac when closing a window; worked around by hiding windows withorderOut:instead of destroying them. - firebase/firebase-ios-sdk#9371 — the same exception when a responder's class is modified at runtime. For context,
gpui-baseinstallsaccessibilityHitTest:on the window's class viaclass_addMethodinmacos_accessibility.rs; I have not shown that this is involved.
Thanks for the thorough report. Looking at what gpui-kit does on macOS, I don't think
gpui-baseis involved:install_window_hit_test_forwarder(crates/base/src/macos_accessibility.rs) only callsclass_addMethodto addaccessibilityHitTest:to the window's class. It never changes an object's isa (object_setClass), and it doesn't touch anyNSView,nextResponder, or the view hierarchy. The firebase-ios-sdk#9371 failure comes from swapping the class of the observed object, which breaks its KVO registration. That isn't happening here.gpui-pre-macos) doesn't touch the responder chain or the Touch Bar either. The only place it adds or removes views at runtime is theBlurredViewwhen a window's background appearance switches to or fromBlurred.Together with navop#268 hitting the same exception in another GPUI app, this looks like a timing issue between AppKit's Touch Bar finder and GPUI windows or views being created, destroyed, or activated. It's in the GPUI platform layer (or AppKit itself), and there's nothing gpui-kit can change for it. If you can narrow it down, the most useful details would be:
WindowBackgroundAppearance::Blurredor switches background appearance at runtime;.ipscrash report from~/Library/Logs/DiagnosticReports, including the other threads.If it turns out to be GPUI's macOS window/view lifecycle, it should be reported to zed-industries/zed, since the
gpui-precrates are unmodified upstream snapshots.