libnyanpasu/clash-nyanpasu · error
failed to get delegate
Error message
failed to get delegate
What it means
`WindowDelegate::new` reads the NSWindow's existing delegate via `win.delegate()` and expects it to be present, storing it as `super_class` so the custom `TrafficLightsWindowDelegate` can forward messages. The panic means Tauri's window had no delegate installed yet (or the objc message returned nil). Without the original delegate, message forwarding would break, so the code treats it as fatal.
Source
Thrown at backend/tauri/src/window.rs:1101
self.ivars().app_box.apply_traffic_lights_pos();
tracing::trace!("passthrough `windowDidExitFullScreen` to TAO layer");
unsafe { self.ivars().super_class.windowDidExitFullScreen(notification) }
}
#[unsafe(method(windowDidFailToEnterFullScreen:))]
unsafe fn windowDidFailToEnterFullScreen(&self,window: &NSWindow) {
tracing::trace!("passthrough `windowDidFailToEnterFullScreen` to TAO layer");
unsafe { self.ivars().super_class.windowDidFailToEnterFullScreen(window) }
}
}
}
impl WindowDelegate {
pub fn new(window_state: WindowState, mtm: MainThreadMarker) -> Retained<Self> {
let this = Self::alloc(mtm);
let super_class = window_state
.with_ns_window(|win| unsafe { win.delegate().expect("failed to get delegate") });
let ivars = TrafficLightsWindowDelegateIvars {
app_box: window_state,
super_class,
};
let this = this.set_ivars(ivars);
unsafe { msg_send![super(this), init] }
}
}
pub struct TrafficLightsWindowDelegateGuard {
_delegate: Retained<WindowDelegate>,
}
thread_local! {
/// This is used to keep the delegate alive until the window is destroyed
static TRAFFIC_LIGHTS_WINDOW_DELEGATE_GUARD: RefCell<Option<TrafficLightsWindowDelegateGuard>> = const { RefCell::new(None) };
}
View on GitHub (pinned to f7dbce2997)
Solutions
- Defer `WindowDelegate::new` until after the window is fully created and shown (e.g. hook it on a setup/ready event, not during construction).
- Check WRY/Tauri versions: ensure the delegate installation timing matches this code's assumption; upgrade or add a readiness wait.
- Fall back to a nil super_class with degraded behavior (log + skip forwarding) instead of panicking if a delegate is genuinely absent.
- If it persists, intercept earlier in window creation so the custom delegate wraps the delegate before it is consumed.
Example fix
// before
let super_class = window_state
.with_ns_window(|win| unsafe { win.delegate().expect("failed to get delegate") });
// after
let super_class = window_state
.with_ns_window(|win| unsafe { win.delegate() })
.unwrap_or_else(|| {
tracing::warn!("window has no delegate yet; deferring traffic lights");
// defer or skip delegate wrapping
todo!("handle missing delegate gracefully")
}); Defensive patterns
Strategy: fallback
Validate before calling
// call only after window setup completes
let has_delegate = window_state.with_ns_window(|win| unsafe { win.delegate().is_some() });
if !has_delegate {
tracing::warn!("no delegate installed yet; defer WindowDelegate::new");
} Type guard
fn window_has_delegate(window_state: &WindowState) -> bool {
window_state.with_ns_window(|win| unsafe { win.delegate().is_some() })
} Try / catch
match window_state.with_ns_window(|win| unsafe { win.delegate() }) {
Some(delegate) => { /* proceed with wrapping */ }
None => {
tracing::warn!("delegate missing; deferring traffic-light delegate setup");
return None;
}
} Prevention
- Install the custom delegate in the Tauri setup hook after window creation completes
- Pin WRY/Tauri versions and re-verify delegate installation timing on upgrades
- Never call delegate-dependent setup from background threads
When it happens
Trigger: Constructing `WindowDelegate` (macOS traffic-light feature init) before Tauri/WRY installs its own NSWindow delegate, or after it has been replaced/cleared; calling this during early window setup on a not-yet-fully-initialized window.
Common situations: Applying the delegate at app startup ahead of WRY's window configuration; Tauri/WRY version changes that moved when the delegate is installed; creating the window with configurations that skip the default delegate.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- failed to retain window
- failed to set traffic lights pos
- URL event received before prepare() was called
- listen() called before prepare()
- prepare() called more than once with different identifiers.
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/c9430a0e97778900.
Report an issue: GitHub.