{"record":{"id":"a0b5e01906d6a084","repo":"cjpais/Handy","slug":"failed-to-create-unload-model-item","errorCode":null,"errorMessage":"failed to create unload model item","messagePattern":"failed to create unload model item","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/src/tray.rs","lineNumber":281,"sourceCode":"    }\n\n    let desired = compute_desired(app, icon_state);\n\n    // Decode the icon off the main thread, once per path, outside the lock.\n    let needs_icon = !state.lock().icons.contains_key(desired.icon_path);\n    let loaded_icon = if needs_icon {\n        match load_tray_icon(\n            app.path()\n                .resolve(desired.icon_path, tauri::path::BaseDirectory::Resource),\n        ) {\n            Ok(image) => Some(image),\n            Err(err) => {\n                error!(\"Failed to load tray icon '{}': {err}\", desired.icon_path);\n                None\n            }\n        }\n    } else {\n        None\n    };\n\n    let schedule = {\n        let mut inner = state.lock();\n        if let Some(image) = loaded_icon {\n            inner.icons.insert(desired.icon_path, image);\n        }\n        if seq < inner.desired_seq {\n            // A request triggered after this one already stored its snapshot\n            // (and scheduled an apply). Ours is stale; drop it.\n            trace!(\n                \"tray sync: request {seq} superseded by {}\",\n                inner.desired_seq\n            );\n            return;\n        }\n        inner.desired = Some(desired);\n        inner.desired_seq = seq;","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/cjpais/Handy/blob/fbd4e15fa14a721c66c57006ae110428b9e255b3/src-tauri/src/tray.rs#L263-L299","documentation":"The unload-model MenuItem is created with enabled = model_loaded (queried from TranscriptionManager). The enabled flag only affects grey-out state, not creation success, so this .expect panics under the same general conditions as the other items: the native menu backend (muda via Tauri) refusing to register the item — overwhelmingly a Linux tray/DBusMenu availability problem or a teardown race.","triggerScenarios":"Any update_tray_menu rebuild on a system lacking a StatusNotifierWatcher; a rebuild triggered by model load/unload completing while the tray backend is gone; invoking the builder after the app handle's event loop has dropped.","commonSituations":"GNOME without an AppIndicator extension; sway/niri/Hyprland without a bar providing tray; testing on Wayland sessions where Tauri's tray support is limited.","solutions":["Run the app inside a desktop session with a functional system tray when exercising tray code paths","Make update_tray_menu fallible: on item-creation error, log and abort the rebuild keeping the previous menu","Feature-test tray availability once at startup and skip rebuilds (hide tray, rely on --no-tray mode) when unavailable","Avoid triggering update_tray_menu from model unload paths during shutdown"],"exampleFix":"// before\nlet unload_model_i = MenuItem::with_id(\n    app, \"unload_model\", &strings.unload_model, model_loaded, None::<&str>,\n)\n.expect(\"failed to create unload model item\");\n\n// after\nlet unload_model_i = MenuItem::with_id(\n    app, \"unload_model\", &strings.unload_model, model_loaded, None::<&str>,\n)\n.unwrap_or_else(|e| {\n    warn!(\"Failed to create unload model item: {e}\");\n    return; // caller aborts rebuild, old tray stays\n});","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"let Ok(unload_model_i) = MenuItem::with_id(\n    app, \"unload_model\", &strings.unload_model, model_loaded, None::<&str>,\n) else { error!(\"unload item failed; aborting rebuild\"); return; };","preventionTips":["Remember enabled=false items still require successful creation — the model_loaded flag is not a guard","Route every menu constructor through a common fallible helper so no call site can .expect","Test tray rebuilds on all three target OSes, especially Linux with and without a tray applet"],"tags":["tauri","tray","muda","rust","panic","linux"],"backgroundTag":"tauri-tray-menu-creation-failed","analyzedSha":"fbd4e15fa14a721c66c57006ae110428b9e255b3","analyzedAt":"2026-08-17T10:29:55.597Z","contentChangedAt":"2026-08-17T10:29:55.597Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}