glzr-io/glazewm · error
Invalid tray menu event
Error message
Invalid tray menu event: {} What it means
`SystemTrayEvent::from_str` parses menu-item IDs that the system tray sends back over an mpsc channel. Each known ID maps to an enum variant; any unrecognized string (typo, stale ID, event from a different version, or corrupt payload) fails to parse and bails with the raw event text. The library only accepts the exact set of menu IDs it registered.
Solutions
- Check the event string in the error message against the supported IDs (show_config_folder, reload_config, toggle_window_animations, run_on_startup, exit) and use an exact match.
- Update GlazeWM/config so both sides agree on the menu item IDs.
- If adding a new tray item, add a matching arm in `from_str` and register the same ID when building the menu.
- Clear stale tray state (restart the app) so old registered menu IDs are not replayed.
Example fix
// before
tray.add_menu_item("reload-conf");
// after
tray.add_menu_item("reload_config"); Defensive patterns
Strategy: validation
Validate before calling
const VALID_IDS: &[&str] = &["show_config_folder","reload_config","toggle_window_animations","run_on_startup","exit"];
fn is_valid_tray_id(id: &str) -> bool { VALID_IDS.contains(&id) } Type guard
fn parse_tray_event(id: &str) -> Option<SystemTrayEvent> { SystemTrayEvent::from_str(id).ok() } Try / catch
let event = match SystemTrayEvent::from_str(id) {
Ok(e) => e,
Err(_) => { tracing::warn!("Unknown tray event: {}", id); return; }
}; Prevention
- Use the enum's IDs (not hand-written strings) when registering menu items.
- Keep menu registration and `from_str` arms in sync when adding items.
- Restart the tray after upgrading so IDs from old builds don't replay.
When it happens
Trigger: A tray menu click produces an ID string not present in the match arms — e.g. `"show_config_folderx"`, an ID added by a plugin/newer build, or a malformed message delivered on the tray event channel.
Common situations: Running mismatched versions of the tray/IPC components (config referencing a menu item that no longer exists); typos when adding new menu items; custom builds where menu IDs were renamed without updating both sides.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Invalid regex.
- Not a valid tiling direction
- Shell exec failed for
- Root container does not have a position.
- Cannot run command because subject container is detached.
AI-assisted analysis of glzr-io/glazewm@5709ad0a3c (2026-09-08).
Data as JSON: /api/errors/b593e805d122be61.
Report an issue: GitHub.
Appendix: source
Thrown at packages/wm/src/sys_tray.rs:55
}
TrayMenuId::RunOnStartup => write!(f, "run_on_startup"),
TrayMenuId::Exit => write!(f, "exit"),
}
}
}
impl FromStr for TrayMenuId {
type Err = anyhow::Error;
fn from_str(event: &str) -> Result<Self, Self::Err> {
match event {
"show_config_folder" => Ok(Self::ShowConfigFolder),
"reload_config" => Ok(Self::ReloadConfig),
#[cfg(target_os = "windows")]
"toggle_window_animations" => Ok(Self::ToggleWindowAnimations),
"run_on_startup" => Ok(Self::RunOnStartup),
"exit" => Ok(Self::Exit),
_ => anyhow::bail!("Invalid tray menu event: {}", event),
}
}
}
pub struct SystemTray {
pub config_reload_rx: mpsc::UnboundedReceiver<()>,
pub exit_rx: mpsc::UnboundedReceiver<()>,
_icon_thread: Option<std::thread::JoinHandle<()>>,
_tray_icon: ThreadBound<TrayIcon>,
}
impl SystemTray {
/// Install the system tray on the main thread after the run loop starts.
pub fn new(
config_path: &Path,
dispatcher: Dispatcher,
) -> anyhow::Result<Self> {
let (exit_tx, exit_rx) = mpsc::unbounded_channel();
View on GitHub (pinned to 5709ad0a3c)