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

  1. Defer `WindowDelegate::new` until after the window is fully created and shown (e.g. hook it on a setup/ready event, not during construction).
  2. Check WRY/Tauri versions: ensure the delegate installation timing matches this code's assumption; upgrade or add a readiness wait.
  3. Fall back to a nil super_class with degraded behavior (log + skip forwarding) instead of panicking if a delegate is genuinely absent.
  4. 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

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


AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/c9430a0e97778900. Report an issue: GitHub.