diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,7 @@
+### 0.26.6
+
++ Work around changing conventions about what the `closure n` annotation means: many annotations appear on the callback, pointing to the user_data argument, but sometimes it also appears on the user_data argument, pointing to the callback. See [issue 407](https://github.com/haskell-gi/haskell-gi/issues/407) for a place where this becomes a problem.
+
 ### 0.26.5
 
 + Add a reference to ?self argument in signals. See [issue 408](https://github.com/haskell-gi/haskell-gi/issues/408) for the motivation.
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.26.5
+version:             0.26.6
 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/Callable.hs b/lib/Data/GI/CodeGen/Callable.hs
--- a/lib/Data/GI/CodeGen/Callable.hs
+++ b/lib/Data/GI/CodeGen/Callable.hs
@@ -584,8 +584,11 @@
                   Nothing -> badIntroError $ "Could not find " <> name
                                 <> " in " <> T.pack (ppShow callable) <> "\n"
                                 <> T.pack (ppShow nameMap)
-       when (argScope arg == ScopeTypeCall) $
-            line $ "safeFreeFunPtr $ castFunPtrToPtr " <> name'
+       when (argScope arg == ScopeTypeCall) $ do
+         isCallback <- typeIsCallback (argType arg)
+         if isCallback
+           then line $ "safeFreeFunPtr $ castFunPtrToPtr " <> name'
+           else comment $ "XXX: Ignoring scope annotation on a non-callback argument: " <> name
 
 -- | Format the signature of the Haskell binding for the `Callable`.
 formatHSignature :: Callable -> ForeignSymbol -> ExposeClosures -> ExcCodeGen ()
diff --git a/lib/Data/GI/CodeGen/CodeGen.hs b/lib/Data/GI/CodeGen/CodeGen.hs
--- a/lib/Data/GI/CodeGen/CodeGen.hs
+++ b/lib/Data/GI/CodeGen/CodeGen.hs
@@ -21,7 +21,8 @@
 import Data.GI.CodeGen.EnumFlags (genEnum, genFlags)
 import Data.GI.CodeGen.Fixups (dropMovedItems, guessPropertyNullability,
                                detectGObject, dropDuplicatedFields,
-                               checkClosureDestructors, fixSymbolNaming)
+                               checkClosureDestructors, fixSymbolNaming,
+                               fixClosures)
 import Data.GI.CodeGen.GObject
 import Data.GI.CodeGen.Haddock (deprecatedPragma, addSectionDocumentation,
                                 writeHaddock,
@@ -553,6 +554,9 @@
       -- destructor for a user_data argument has an associated
       -- user_data argument.
       $ map checkClosureDestructors
+      -- Make sure that the argClosure argument refers to a callback,
+      -- not to the user_data field.
+      $ map fixClosures
       -- Make sure that the symbols to be generated are valid
       -- Haskell identifiers, when necessary.
       $ map fixSymbolNaming
diff --git a/lib/Data/GI/CodeGen/Fixups.hs b/lib/Data/GI/CodeGen/Fixups.hs
--- a/lib/Data/GI/CodeGen/Fixups.hs
+++ b/lib/Data/GI/CodeGen/Fixups.hs
@@ -5,17 +5,20 @@
     , detectGObject
     , dropDuplicatedFields
     , checkClosureDestructors
+    , fixClosures
     , fixSymbolNaming
     ) where
 
 import Data.Char (generalCategory, GeneralCategory(UppercaseLetter))
 import Data.Maybe (isNothing, isJust)
+import qualified Data.Map as M
 #if !MIN_VERSION_base(4,13,0)
 import Data.Monoid ((<>))
 #endif
 import qualified Data.Set as S
 import qualified Data.Text as T
 
+import Data.GI.CodeGen.Type
 import Data.GI.CodeGen.API
 
 -- | Remove functions and methods annotated with "moved-to".
@@ -178,7 +181,7 @@
         checkMethod m = m {methodCallable =
                              checkCallableDestructors (methodCallable m)}
 
--- | If any argument for the callable has a associated destroyer for
+-- | If any argument for the callable has an associated destroyer for
 -- the user_data, but no associated user_data, drop the destroyer
 -- annotation.
 checkCallableDestructors :: Callable -> Callable
@@ -187,6 +190,62 @@
         checkArg arg = if argDestroy arg >= 0 && argClosure arg == -1
                        then arg {argDestroy = -1}
                        else arg
+
+-- | Sometimes it is the callback that is annotated with the (closure
+-- user_data) annotation, and sometimes the user_data parameter
+-- itself, with (closure callback) pointing to the callback. The
+-- following code makes sure that the annotation is on the callable
+-- only. Note that this goes against the official gobject
+-- introspection spec, but there is more code using this convention
+-- than otherwise, and the gir generator seems to add closure
+-- annotations in both directions when using the new convention
+-- anyway.
+fixCallableClosures :: Callable -> Callable
+fixCallableClosures c = c {args = map fixupArg (zip [0..] (args c))}
+  where fixupArg :: (Int, Arg) -> Arg
+        fixupArg (n, arg) = if isUserData arg
+                            then arg {argClosure = -1}
+                            else
+                              case M.lookup n reverseMap of
+                                Just user_data -> arg {argClosure = user_data}
+                                Nothing -> arg
+
+        -- Map from callbacks to their corresponding user_data
+        -- arguments, obtained by looking to the argClosure value for
+        -- the user_data argument.
+        reverseMap :: M.Map Int Int
+        reverseMap = M.fromList
+          . map (\(n, arg) -> (argClosure arg, n))
+          . filter (isUserData . snd)
+          . filter ((/= -1) . argClosure . snd)
+          $ zip [0..] (args c)
+
+        isUserData :: Arg -> Bool
+        isUserData arg = argScope arg == ScopeTypeInvalid ||
+                         argType arg == TBasicType TPtr
+
+-- | Closures are often incorrectly assigned, with the closure
+-- annotation on the callback, instead of in the closure (user_data)
+-- parameter itself. The following makes sure that things are as they
+-- should.
+fixClosures :: (Name, API) -> (Name, API)
+fixClosures (n, APIObject o) =
+  (n, APIObject (o {objMethods = fixMethodClosures (objMethods o)}))
+fixClosures (n, APIInterface i) =
+  (n, APIInterface (i {ifMethods = fixMethodClosures (ifMethods i)}))
+fixClosures (n, APIStruct s) =
+  (n, APIStruct (s {structMethods = fixMethodClosures (structMethods s)}))
+fixClosures (n, APIUnion u) =
+  (n, APIUnion (u {unionMethods = fixMethodClosures (unionMethods u)}))
+fixClosures (n, APIFunction f) =
+  (n, APIFunction (f {fnCallable = fixCallableClosures (fnCallable f)}))
+fixClosures (n, api) = (n, api)
+
+fixMethodClosures :: [Method] -> [Method]
+fixMethodClosures = map fixMethod
+  where fixMethod :: Method -> Method
+        fixMethod m = m {methodCallable =
+                            fixCallableClosures (methodCallable m)}
 
 -- | Some symbols have names that are not valid Haskell identifiers,
 -- fix that here.
