libnyanpasu/clash-nyanpasu · error

update_systray unhandled error

Error message

update_systray unhandled error

What it means

update_systray_part is a static method on the Handle global that reads the stored Tauri AppHandle to refresh the system tray. If the app handle was never stored (app not yet initialized) the method bails with this generic, unhelpful message instead of a typed error. It is an internal invariant violation: tray updates were requested before the app handle exists.

Source

Thrown at backend/tauri/src/core/handle.rs:91

            log_err!(window.emit(NOTIFY_MESSAGE_URI, message));
        }
    }

    pub fn update_systray() -> Result<()> {
        // let app_handle = Self::global().app_handle.lock();
        // if app_handle.is_none() {
        //     bail!("update_systray unhandled error");
        // }
        // Tray::update_systray(app_handle.as_ref().unwrap())?;
        Handle::emit("update_systray", ())?;
        Ok(())
    }

    /// update the system tray state
    pub fn update_systray_part() -> Result<()> {
        let app_handle = Self::global().app_handle.lock();
        if app_handle.is_none() {
            bail!("update_systray unhandled error");
        }
        Tray::update_part(app_handle.as_ref().unwrap())?;
        Ok(())
    }

    pub fn emit<S: Serialize + Clone>(event: &str, payload: S) -> Result<()> {
        let app_handle = Self::global().app_handle.lock();
        if app_handle.is_none() {
            bail!("app_handle is not exist");
        }

        app_handle.as_ref().unwrap().emit(event, payload)?;
        Ok(())
    }
}

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Ensure the caller only invokes tray updates after app setup completes (sequence initialization before event emission)
  2. Make the method a no-op-with-warning when the handle is missing instead of an error, since tray refresh is a UI side effect
  3. Migrate per the actor-migration plan: replace Handle::global() with a UiEventSink/TauriUiEventSink adapter injected at the composition root
  4. Improve the message to state that the app handle is not initialized

Example fix

// before
bail!("update_systray unhandled error");
// after
let Some(app_handle) = app_handle.as_ref() else {
    log::warn!("update_systray skipped: app handle not initialized yet");
    return Ok(());
};
Defensive patterns

Strategy: try-catch

Validate before calling

// caller-side guard
fn tray_ready(handle: &Handle) -> bool {
    handle.app_handle.lock().is_some()
}

Try / catch

if let Err(e) = Handle::update_systray_part() {
    log::warn!("systray update skipped: {e}");
}

Prevention

When it happens

Trigger: Calling Handle::update_systray_part() before setup() stores the AppHandle — e.g. during early startup, config import, or a command racing app initialization; also after a failed shutdown cleared it.

Common situations: Tray update triggered by a config-change event that fires before Tauri setup completes; tests invoking core logic without a Tauri runtime; unit tests calling Handle::global() with no app handle registered.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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