{"record":{"id":"7337715837a7a738","repo":"libnyanpasu/clash-nyanpasu","slug":"tray-not-found","errorCode":null,"errorMessage":"tray not found","messagePattern":"tray not found","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/core/tray/mod.rs","lineNumber":344,"sourceCode":"        Tray::update_part(app_handle)?;\n        Ok(())\n    }\n\n    #[instrument(skip(app_handle))]\n    pub fn update_part<R: Runtime>(app_handle: &AppHandle<R>) -> Result<()> {\n        let mode = crate::utils::config::get_current_clash_mode();\n        let core = {\n            *Config::verge()\n                .latest()\n                .clash_core\n                .as_ref()\n                .unwrap_or(&ClashCore::default())\n        };\n        let tray_id = get_tray_id();\n        tracing::debug!(\"updating tray part: {}\", tray_id);\n        let tray = app_handle\n            .tray_by_id(tray_id.as_ref())\n            .expect(\"tray not found\");\n        let state = app_handle.state::<TrayState<R>>();\n        let menu = state.menu.lock();\n\n        let _ = menu\n            .get(\"rule_mode\")\n            .and_then(|item| item.as_check_menuitem()?.set_checked(mode == \"rule\").ok());\n        let _ = menu\n            .get(\"global_mode\")\n            .and_then(|item| item.as_check_menuitem()?.set_checked(mode == \"global\").ok());\n        let _ = menu\n            .get(\"direct_mode\")\n            .and_then(|item| item.as_check_menuitem()?.set_checked(mode == \"direct\").ok());\n        if core == ClashCore::ClashPremium {\n            let _ = menu\n                .get(\"script_mode\")\n                .and_then(|item| item.as_check_menuitem()?.set_checked(mode == \"script\").ok());\n        }\n","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/core/tray/mod.rs#L326-L362","documentation":"update_part looks up the app's tray by its tray ID and panics with 'tray not found' when tray_by_id returns None. It assumes the tray icon was already created during setup; updating menu/tooltip state on a tray that was never built (or was destroyed) is an unrecoverable invariant violation in this code path.","triggerScenarios":"Calling update_part (e.g. from proxy mode/config change handlers) before tray creation completes, after the tray was closed/destroyed, or when get_tray_id() yields an ID that doesn't match the registered tray (rebuild after core switch, plugin re-init).","commonSituations":"Config or clash-core change event firing during early startup before setup() created the tray; tray creation silently failed earlier (e.g. missing tray icon resources); multiple update_part calls racing with tray rebuild on Windows.","solutions":["Create/register the tray in setup() before any service can emit update_part calls","Replace the .expect with early return + warning log when the tray is absent","Verify get_tray_id() matches the ID used at tray creation","Gate tray update handlers until a TrayState/created flag is set"],"exampleFix":"// before\nlet tray = app_handle\n    .tray_by_id(tray_id.as_ref())\n    .expect(\"tray not found\");\n// after\nlet Some(tray) = app_handle.tray_by_id(tray_id.as_ref()) else {\n    tracing::warn!(\"tray not found, skipping update_part\");\n    return Ok(());\n};","handlingStrategy":"fallback","validationCode":"if app_handle.tray_by_id(get_tray_id()).is_none() {\n    tracing::warn!(\"tray not yet created; skipping update\");\n    return;\n}","typeGuard":null,"tryCatchPattern":"match app_handle.tray_by_id(tray_id.as_ref()) {\n    Some(tray) => { /* update */ }\n    None => tracing::warn!(\"tray not found; skipping update_part\"),\n}","preventionTips":["Create the tray in setup() before wiring update handlers","Never assume tray exists on every platform; guard all update paths","Keep tray IDs consistent between creation and lookup"],"tags":["tauri","tray","panic","initialization-order"],"backgroundTag":"entity-not-found","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}