diff --git a/gtk-sni-tray.cabal b/gtk-sni-tray.cabal
--- a/gtk-sni-tray.cabal
+++ b/gtk-sni-tray.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           gtk-sni-tray
-version:        0.1.10.2
+version:        0.1.10.3
 synopsis:       A standalone StatusNotifierItem/AppIndicator tray
 description:    Please see the README on Github at <https://github.com/IvanMalison/gtk-sni-tray#readme>
 category:       System
diff --git a/src/StatusNotifier/DBusMenu.hs b/src/StatusNotifier/DBusMenu.hs
--- a/src/StatusNotifier/DBusMenu.hs
+++ b/src/StatusNotifier/DBusMenu.hs
@@ -3,6 +3,7 @@
   ( buildMenu
   ) where
 
+import Control.Exception.Enclosed (catchAny)
 import Control.Monad (forM_, when)
 import Data.Int (Int32)
 import Data.Map.Strict (Map)
@@ -15,6 +16,7 @@
 import Data.GI.Base (unsafeCastTo)
 import qualified GI.Gtk as Gtk
 import System.Log.Logger (Priority(..), logM)
+import Text.Printf
 
 dbusMenuLogger :: Priority -> String -> IO ()
 dbusMenuLogger = logM "StatusNotifier.DBusMenu"
@@ -171,9 +173,13 @@
   -- Submenu handling: build children now, and refresh on show via AboutToShow/GetLayout.
   if null (lnChildren node)
     then do
-      _ <- Gtk.onMenuItemActivate item $ do
-        ts <- Gtk.getCurrentEventTime
-        sendClicked client dest path (lnId node) ts
+      _ <- Gtk.onMenuItemActivate item $
+        catchAny
+          (do ts <- Gtk.getCurrentEventTime
+              sendClicked client dest path (lnId node) ts)
+          (\e -> dbusMenuLogger WARNING $
+                 printf "Menu item %d click failed (stale ID?): %s"
+                        (lnId node) (show e))
       pure ()
     else do
       addCssClass itemW "tray-menu-item-has-submenu"
@@ -184,12 +190,16 @@
       -- Populate with the eagerly-fetched layout so submenus are usable even if
       -- the service doesn't support/require lazy updates.
       populateGtkMenu client dest path submenu node
-      let refresh = do
-            -- Allow the service to update the submenu content lazily.
-            _ <- aboutToShow client dest path (lnId node)
-            (_, layout) <- getLayout client dest path (lnId node) 1 []
-            populateGtkMenu client dest path submenu layout
-            Gtk.widgetShowAll submenu
+      let refresh =
+            catchAny
+              (do -- Allow the service to update the submenu content lazily.
+                  _ <- aboutToShow client dest path (lnId node)
+                  (_, layout) <- getLayout client dest path (lnId node) 1 []
+                  populateGtkMenu client dest path submenu layout
+                  Gtk.widgetShowAll submenu)
+              (\e -> dbusMenuLogger WARNING $
+                     printf "Submenu %d refresh failed (stale ID?): %s"
+                            (lnId node) (show e))
       _ <- Gtk.onWidgetShow submenu refresh
       Gtk.menuItemSetSubmenu item (Just submenu)
 
diff --git a/src/StatusNotifier/Tray.hs b/src/StatusNotifier/Tray.hs
--- a/src/StatusNotifier/Tray.hs
+++ b/src/StatusNotifier/Tray.hs
@@ -72,22 +72,25 @@
   height <- pixbufGetHeight pixbuf
   let warnAndReturnOrig =
         trayLogger WARNING "Unable to scale pixbuf" >> return pixbuf
-      targetWidth = case orientation of
-                      Gtk.OrientationHorizontal -> False
-                      _ -> True
-      (scaledWidth, scaledHeight) =
-        getScaledWidthHeight targetWidth size width height
-  trayLogger DEBUG $
-             printf
-             "Scaling pb to %s, actualW: %s, actualH: %s, scaledW: %s, scaledH: %s"
-             (show size) (show width) (show height)
-             (show scaledWidth) (show scaledHeight)
-
-  trayLogger DEBUG $ printf "targetW: %s, targetH: %s"
+  if width <= 0 || height <= 0
+  then warnAndReturnOrig
+  else do
+    let targetWidth = case orientation of
+                        Gtk.OrientationHorizontal -> False
+                        _ -> True
+        (scaledWidth, scaledHeight) =
+          getScaledWidthHeight targetWidth size width height
+    trayLogger DEBUG $
+               printf
+               "Scaling pb to %s, actualW: %s, actualH: %s, scaledW: %s, scaledH: %s"
+               (show size) (show width) (show height)
                (show scaledWidth) (show scaledHeight)
-  maybe warnAndReturnOrig return =<<
-    pixbufScaleSimple pixbuf scaledWidth scaledHeight InterpTypeBilinear
 
+    trayLogger DEBUG $ printf "targetW: %s, targetH: %s"
+                 (show scaledWidth) (show scaledHeight)
+    maybe warnAndReturnOrig return =<<
+      pixbufScaleSimple pixbuf scaledWidth scaledHeight InterpTypeBilinear
+
 themeLoadFlags :: [IconLookupFlags]
 themeLoadFlags = [IconLookupFlagsGenericFallback, IconLookupFlagsUseBuiltin]
 
@@ -174,14 +177,18 @@
     return $ (themePath </>) <$> find (isPrefixOf name) fileNames
   else return Nothing
 
-getIconPixbufFromByteString :: Int32 -> Int32 -> BS.ByteString -> IO Pixbuf
-getIconPixbufFromByteString width height byteString = do
-  trayLogger DEBUG "Getting Pixbuf from bytestring"
-  bytes <- bytesNew $ Just byteString
-  let bytesPerPixel = 4
-      rowStride = width * bytesPerPixel
-      sampleBits = 8
-  pixbufNewFromBytes bytes ColorspaceRgb True sampleBits width height rowStride
+getIconPixbufFromByteString :: Int32 -> Int32 -> BS.ByteString -> IO (Maybe Pixbuf)
+getIconPixbufFromByteString width height byteString
+  | width <= 0 || height <= 0 = do
+      trayLogger WARNING $ printf "Invalid icon dimensions: %dx%d" width height
+      return Nothing
+  | otherwise = catchGErrorsAsNothing $ do
+      trayLogger DEBUG "Getting Pixbuf from bytestring"
+      bytes <- bytesNew $ Just byteString
+      let bytesPerPixel = 4
+          rowStride = width * bytesPerPixel
+          sampleBits = 8
+      pixbufNewFromBytes bytes ColorspaceRgb True sampleBits width height rowStride
 
 data ItemContext = ItemContext
   { contextName :: DBusTypes.BusName
@@ -379,18 +386,25 @@
                    itemIsMenu True serviceName
               2 -> return middleClickAction
               _ -> return rightClickAction
+            let logActionError actionName e =
+                  trayLogger WARNING $ printf "%s failed for %s: %s"
+                    (actionName :: String)
+                    (coerce serviceName :: String)
+                    (show e)
             case action of
-              Activate -> void $ IC.activate client serviceName servicePath x y
-              SecondaryActivate -> void $ IC.secondaryActivate client
-                                   serviceName servicePath x y
+              Activate -> catchAny
+                (void $ IC.activate client serviceName servicePath x y)
+                (logActionError "Activate")
+              SecondaryActivate -> catchAny
+                (void $ IC.secondaryActivate client
+                        serviceName servicePath x y)
+                (logActionError "SecondaryActivate")
               PopupMenu -> do
                 menuPath' <- getInfoAttr menuPath Nothing serviceName
                 traverse_
                   (\p -> catchAny
                     (DBusMenu.buildMenu client serviceName p >>= (`popupGtkMenu` event))
-                    (\e -> trayLogger WARNING $ printf "Failed to build menu for %s: %s"
-                      (coerce serviceName :: String)
-                      (show e)))
+                    (logActionError "PopupMenu"))
                   menuPath'
             return False
           _ <- Gtk.onWidgetScrollEvent eventBox $ \event -> do
@@ -409,7 +423,10 @@
                           ScrollDirectionLeft -> -1
                           ScrollDirectionRight -> 1
                           _ -> 0
-            traverse_ (IC.scroll client serviceName servicePath delta) direction'
+            traverse_ (\d -> catchAny
+              (void $ IC.scroll client serviceName servicePath delta d)
+              (\e -> trayLogger WARNING $ printf "Scroll failed for %s: %s"
+                (coerce serviceName :: String) (show e))) direction'
             return False
 
           MV.modifyMVar_ contextMap $ return . Map.insert serviceName context
@@ -492,15 +509,19 @@
               else minimumBy orderer largeEnough
             getFromPixmaps (w, h, p) =
               if BS.length p == 0
-              then Nothing
-              else Just $ getIconPixbufFromByteString w h p
+              then return Nothing
+              else getIconPixbufFromByteString w h p
         if null pixmaps
         then getIconPixbufByName size (T.pack name) mpath
-        else sequenceA $ getFromPixmaps selectedPixmap
+        else getFromPixmaps selectedPixmap
 
       uiUpdateHandler updateType info =
         void $ Gdk.threadsAddIdle GLib.PRIORITY_DEFAULT $
-             updateHandler updateType info >> return False
+             catchAny
+               (updateHandler updateType info >> return False)
+               (\e -> do
+                 trayLogger WARNING $ printf "Update handler failed: %s" (show e)
+                 return False)
 
   handlerId <- addUHandler uiUpdateHandler
   _ <- Gtk.onWidgetDestroy trayBox $ removeUHandler handlerId
