DioxusLabs/dioxus · error

tray icon builder failed

Error message

tray icon builder failed

What it means

init_tray_icon builds the OS tray icon with tray-icon's TrayIconBuilder and unwraps the Result. On Linux the tray depends on the StatusNotifierItem protocol over dbus; on other desktops it depends on system APIs. When creation fails (no tray service reachable, wrong environment) the app panics at startup. Icon decoding errors are tolerated - only builder failure is fatal.

Source

Thrown at packages/desktop/src/trayicon.rs:45

#[allow(unused)]
pub fn init_tray_icon(menu: DioxusTrayMenu, icon: Option<DioxusTrayIcon>) -> DioxusTray {
    #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
    {
        let icon = icon.map(Ok).unwrap_or_else(crate::default_icon);

        let tray = tray_icon::TrayIconBuilder::new()
            .with_menu(Box::new(menu))
            .with_menu_on_left_click(false);

        let tray = match icon {
            Ok(icon) => tray.with_icon(icon),
            Err(err) => {
                tracing::trace!("No tray icon: {:?}", err);
                tray
            }
        };

        provide_context(tray.build().expect("tray icon builder failed"))
    }
}

/// Returns a default tray icon menu
pub fn default_tray_icon() -> DioxusTrayMenu {
    #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
    {
        use tray_icon::menu::{Menu, PredefinedMenuItem};
        let tray_menu = Menu::new();
        tray_menu
            .append_items(&[&PredefinedMenuItem::quit(None)])
            .unwrap();
        tray_menu
    }
}

/// Provides a hook to the tray icon
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]

View on GitHub (pinned to 393d190a80)

Solutions

  1. Run the app inside a desktop session with a working tray (KDE, GNOME plus AppIndicator/Tray Icons extension, or a standalone tray)
  2. Make the tray optional: only call init_tray_icon behind a CLI flag or runtime environment check
  3. Elsewhere, use the safe hook use_tray_icon() -> Option<TrayIcon> so absence is handled gracefully
  4. As a last resort wrap the init call in std::panic::catch_unwind so a tray-less environment does not kill the app

Example fix

// before
init_tray_icon(default_tray_icon(), None);

// after
use dioxus_desktop::tao::platform::unix::...
let tray_ok = std::panic::catch_unwind(|| init_tray_icon(default_tray_icon(), None)).is_ok();
if !tray_ok { tracing::warn!("system tray unavailable; continuing without it"); }
Defensive patterns

Strategy: fallback

Validate before calling

// Only create the tray when a desktop session plausibly has one
fn tray_probably_available() -> bool {
    #[cfg(target_os = "linux")]
    {
        std::env::var("XDG_CURRENT_DESKTOP").is_ok() && std::env::var("DISPLAY").is_ok()
    }
    #[cfg(not(target_os = "linux"))]
    { true }
}

Try / catch

// Keep the app alive when the environment has no tray
let tray = std::panic::catch_unwind(|| {
    init_tray_icon(default_tray_icon(), None)
});
if tray.is_err() { tracing::warn!("no system tray; running without tray icon"); }

Prevention

When it happens

Trigger: Calling init_tray_icon on a Linux session without a system tray (bare window manager, GNOME without an AppIndicator extension, headless/WSL sessions) or in an environment where the tray backend cannot initialize.

Common situations: Developing or CI-running a tray-enabled desktop app headlessly; distros without an SNI provider installed; GNOME default session which ships no tray.

Related errors


AI-assisted analysis of DioxusLabs/dioxus@393d190a80 (2026-08-16). Data as JSON: /api/errors/c41adba795153cc3. Report an issue: GitHub.