{"record":{"id":"73da75ff2eed1167","repo":"elkowar/eww","slug":"no-pixbuf-from-theme-load-icon-despite-no-error","errorCode":null,"errorMessage":"no pixbuf from theme.load_icon despite no error","messagePattern":"no pixbuf from theme\\.load_icon despite no error","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/notifier_host/src/icon.rs","lineNumber":115,"sourceCode":"\n/// Load an icon with a given name from either the default (if `theme_path` is `None`), or from the\n/// theme at a path.\nfn icon_from_name(\n    icon_name: &str,\n    theme_path: Option<&str>,\n    size: i32,\n    scale: i32,\n) -> std::result::Result<gtk::gdk_pixbuf::Pixbuf, IconError> {\n    let theme = if let Some(path) = theme_path {\n        let theme = gtk::IconTheme::new();\n        theme.prepend_search_path(path);\n        theme\n    } else {\n        gtk::IconTheme::default().expect(\"Could not get default gtk theme\")\n    };\n\n    match theme.load_icon_for_scale(icon_name, size, scale, gtk::IconLookupFlags::FORCE_SIZE) {\n        Ok(pb) => Ok(pb.expect(\"no pixbuf from theme.load_icon despite no error\")),\n        Err(e) => Err(IconError::LoadIconFromTheme {\n            icon_name: icon_name.to_owned(),\n            theme_path: theme_path.map(str::to_owned),\n            source: e,\n        }),\n    }\n}\n\npub async fn load_icon_from_sni(\n    sni: &proxy::StatusNotifierItemProxy<'_>,\n    size: i32,\n    scale: i32,\n) -> Option<gtk::gdk_pixbuf::Pixbuf> {\n    // \"Visualizations are encouraged to prefer icon names over icon pixmaps if both are\n    // available.\"\n\n    let scaled_size = size * scale;\n","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/elkowar/eww/blob/48f5aa8b379adf29da0b0bb9ca04164f65d8bdaa/crates/notifier_host/src/icon.rs#L97-L133","documentation":"This is an .expect() on the Option inside Ok(pb) from theme.load_icon_for_scale: the GTK docs say that when load_icon_for_scale returns Ok the pixbuf may still be None. GTK yields Ok(None) in edge cases (e.g. the icon resolved to nothing usable for the requested size/scale, such as an empty or malformed icon theme entry), so the crate treats it as an internal invariant violation and panics.","triggerScenarios":"load_icon_from_sni -> icon_from_name calls theme.load_icon_for_scale(icon_name, size, scale, FORCE_SIZE) and GTK returns Ok(None) — observed with icon names that do not resolve cleanly in the (possibly custom, theme_path-prepended) theme at the requested size/scale.","commonSituations":"Tray items advertising icon names absent from the theme while the theme lookup still 'succeeds'; HiDPI scale factors where no scaled variant exists; custom theme paths (prepend_search_path) pointing at incomplete icon theme directories; broken cached pixbufs in some GTK versions.","solutions":["Treat Ok(None) as a lookup failure: fall back to the fallback_icon('image-missing') path instead of panicking","Validate the icon name / theme_path from the SNI item and log it when the lookup yields None","Update GTK (gtk3/glib) packages — some versions had Ok(None) quirks with FORCE_SIZE at unusual scale factors","Map None to an IconError (e.g. IconError::NotAvailable) so callers can degrade gracefully","Ensure a complete icon theme is installed so lookups resolve for all sizes/scales"],"exampleFix":"// before\nOk(pb) => Ok(pb.expect(\"no pixbuf from theme.load_icon despite no error\")),\n// after\nOk(Some(pb)) => Ok(pb),\nOk(None) => {\n    log::warn!(\"theme returned no pixbuf for \\\"{}\\\" at {}px\", icon_name, size);\n    Err(IconError::NotAvailable)\n}","handlingStrategy":"fallback","validationCode":"// Validate inputs before the lookup\nif icon_name.trim().is_empty() { return Err(IconError::NotAvailable); }\nif let Some(p) = theme_path {\n    if !std::path::Path::new(p).exists() { log::warn!(\"theme path missing: {}\", p); }\n}","typeGuard":"fn pixbuf_from_ok(pb: Option<gtk::gdk_pixbuf::Pixbuf>) -> Option<gtk::gdk_pixbuf::Pixbuf> {\n    pb.filter(|p| p.width() > 0 && p.height() > 0)\n}","tryCatchPattern":"match theme.load_icon_for_scale(icon_name, size, scale, gtk::IconLookupFlags::FORCE_SIZE) {\n    Ok(Some(pb)) => Ok(pb),\n    Ok(None) | Err(_) => fallback_icon(size, scale)\n        .map(Ok)\n        .unwrap_or(Err(IconError::NotAvailable)),\n}","preventionTips":["Never assume Ok implies Some: handle the Option from load_icon_for_scale explicitly","Fall back to the 'image-missing' icon when any lookup yields None","Sanitize icon names and theme paths from untrusted SNI items","Install a complete icon theme (adwaita/breeze) so lookups resolve at all sizes and scales","Unit-test lookups at common scale factors (1x, 2x) against the target theme"],"tags":["gtk","rust","panic","icon-theme","pixbuf","invariant-violation"],"backgroundTag":"internal-invariant-violation","analyzedSha":"48f5aa8b379adf29da0b0bb9ca04164f65d8bdaa","analyzedAt":"2026-09-08T03:13:26.897Z","contentChangedAt":"2026-09-08T03:13:26.897Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}