diff --git a/haskell-gi.cabal b/haskell-gi.cabal
--- a/haskell-gi.cabal
+++ b/haskell-gi.cabal
@@ -1,5 +1,5 @@
 name:                haskell-gi
-version:             0.24.0
+version:             0.24.1
 synopsis:            Generate Haskell bindings for GObject Introspection capable libraries
 description:         Generate Haskell bindings for GObject Introspection capable libraries. This includes most notably
                      Gtk+, but many other libraries in the GObject ecosystem provide introspection data too.
diff --git a/lib/Data/GI/CodeGen/API.hs b/lib/Data/GI/CodeGen/API.hs
--- a/lib/Data/GI/CodeGen/API.hs
+++ b/lib/Data/GI/CodeGen/API.hs
@@ -154,6 +154,8 @@
 -- | A rule for modifying the GIR file.
 data GIRRule = GIRSetAttr (GIRPath, XML.Name) Text -- ^ (Path to element,
                                                    -- attrName), newValue.
+             | GIRDeleteAttr GIRPath XML.Name
+             -- ^ Delete the given attribute
              | GIRAddNode GIRPath XML.Name -- ^ Add a child node at
                                            -- the given selector.
              | GIRDeleteNode GIRPath -- ^ Delete any nodes matching
@@ -544,6 +546,8 @@
     where applyGIRRule :: XML.Node -> GIRRule -> Maybe XML.Node
           applyGIRRule n (GIRSetAttr (path, attr) newVal) =
             Just $ girSetAttr (path, attr) newVal n
+          applyGIRRule n (GIRDeleteAttr path attr) =
+            Just $ girDeleteAttr path attr n
           applyGIRRule n (GIRAddNode path new) =
             Just $ girAddNode path new n
           applyGIRRule n (GIRDeleteNode path) =
@@ -565,6 +569,23 @@
                                        (XML.elementNodes elem)})
     else n
 girSetAttr _ _ n = n
+
+-- | Delete an attribute for the child element specified by the given
+-- path, if the attribute exists.
+girDeleteAttr :: GIRPath -> XML.Name -> XML.Node -> XML.Node
+girDeleteAttr (spec:rest) attr n@(XML.NodeElement elem) =
+    if specMatch spec n
+    then case rest of
+           -- Matched the full path, apply
+           [] -> XML.NodeElement (elem {XML.elementAttributes =
+                                        M.delete attr
+                                        (XML.elementAttributes elem)})
+           -- Still some selectors to apply
+           _ -> XML.NodeElement (elem {XML.elementNodes =
+                                       map (girDeleteAttr rest attr)
+                                       (XML.elementNodes elem)})
+    else n
+girDeleteAttr _ _ n = n
 
 -- | Add the given subnode to any nodes matching the given path
 girAddNode :: GIRPath -> XML.Name -> XML.Node -> XML.Node
diff --git a/lib/Data/GI/CodeGen/Callable.hs b/lib/Data/GI/CodeGen/Callable.hs
--- a/lib/Data/GI/CodeGen/Callable.hs
+++ b/lib/Data/GI/CodeGen/Callable.hs
@@ -529,9 +529,9 @@
   forM_ closures $ \closure ->
       case Map.lookup closure m of
         Nothing -> badIntroError $ "Closure not found! "
-                                <> T.pack (ppShow callable)
-                                <> "\n" <> T.pack (ppShow m)
-                                <> "\n" <> tshow closure
+                                <> "\nClosure: " <> tshow closure
+                                <> "\nc2cm: " <> T.pack (ppShow m)
+                                <> "\ncallable: " <> T.pack (ppShow callable)
         Just cb -> do
           let closureName = escapedArgName $ (args callable)!!closure
               n = escapedArgName cb
@@ -556,8 +556,15 @@
                     k -> let destroyName =
                                escapedArgName $ (args callable)!!k in
                            line $ "let " <> destroyName <> " = safeFreeFunPtrPtr"
-                ScopeTypeAsync ->
+                ScopeTypeAsync -> do
                   line $ "let " <> closureName <> " = nullPtr"
+                  case argDestroy cb of
+                    -- Async callbacks don't really need destroy
+                    -- notifications, as they can always be released
+                    -- at the end of the callback.
+                    (-1) -> return ()
+                    n -> let destroyName = escapedArgName $ (args callable)!!n
+                         in line $ "let " <> destroyName <> " = FP.nullFunPtr"
                 ScopeTypeCall -> line $ "let " <> closureName <> " = nullPtr"
             _ -> badIntroError $ "Closure \"" <> n <> "\" is not a callback."
 
diff --git a/lib/Data/GI/CodeGen/Overrides.hs b/lib/Data/GI/CodeGen/Overrides.hs
--- a/lib/Data/GI/CodeGen/Overrides.hs
+++ b/lib/Data/GI/CodeGen/Overrides.hs
@@ -163,6 +163,8 @@
     withFlags $ parseNsVersion s
 parseOneLine (T.stripPrefix "set-attr " -> Just s) =
     withFlags $ parseSetAttr s
+parseOneLine (T.stripPrefix "delete-attr " -> Just s) =
+    withFlags $ parseDeleteAttr s
 parseOneLine (T.stripPrefix "add-node " -> Just s) =
     withFlags $ parseAdd s
 parseOneLine (T.stripPrefix "delete-node " -> Just s) =
@@ -260,6 +262,17 @@
     throwError ("set-attr syntax is of the form\n" <>
                "\t\"set-attr nodePath attrName newValue\"\n" <>
                "Got \"set-attr " <> t <> "\" instead.")
+
+-- | Delete the given attribute
+parseDeleteAttr :: Text -> Parser ()
+parseDeleteAttr (T.words -> [path, attr]) = do
+  pathSpec <- parsePathSpec path
+  parsedAttr <- parseXMLName attr
+  tell $ defaultOverrides {girFixups = [GIRDeleteAttr pathSpec parsedAttr]}
+parseDeleteAttr t =
+    throwError ("delete-attr syntax is of the form\n" <>
+               "\t\"delete-attr nodePath attrName\"\n" <>
+               "Got \"delete-attr " <> t <> "\" instead.")
 
 -- | Add the given child node to all nodes matching the path.
 parseAdd :: Text -> Parser ()
