diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index b4107bd4a2bad..38679aedb94a6 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -503,7 +503,7 @@ struct DiagCtxtInner {
 }
 
 /// A key denoting where from a diagnostic was stashed.
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub enum StashKey {
     ItemNoType,
     UnderscoreForArrayLengths,
@@ -780,7 +780,7 @@ impl DiagCtxt {
             // We delay a bug here so that `-Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs`
             // can be used to create a backtrace at the stashing site insted of whenever the
             // diagnostic context is dropped and thus delayed bugs are emitted.
-            Error => Some(self.span_delayed_bug(span, "stashing {key:?}")),
+            Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
             DelayedBug => return self.inner.borrow_mut().emit_diagnostic(diag),
             ForceWarning(_) | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
             | Expect(_) => None,
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 62711e40049a4..23f6a1f391fe5 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -47,12 +47,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let from = normalize(from);
         let to = normalize(to);
         trace!(?from, ?to);
+
         if from.has_non_region_infer() || to.has_non_region_infer() {
-            // Note: this path is currently not reached in any test, so any
-            // example that triggers this would be worth minimizing and
-            // converting into a test.
-            tcx.dcx().span_bug(span, "argument to transmute has inference variables");
+            // An argument may have an infer var in it but *not* trigger an
+            // ambiguity error yet... See `ambiguity-in-closure-arg.rs` test.
+            tcx.dcx().span_delayed_bug(span, "argument to transmute has inference variables");
+            return;
         }
+
         // Transmutes that are only changing lifetimes are always ok.
         if from == to {
             return;
diff --git a/tests/ui/transmute/ambiguity-in-closure-arg.rs b/tests/ui/transmute/ambiguity-in-closure-arg.rs
new file mode 100644
index 0000000000000..4c2d1ce2ad463
--- /dev/null
+++ b/tests/ui/transmute/ambiguity-in-closure-arg.rs
@@ -0,0 +1,11 @@
+// Minimized test for <https://github.com/rust-lang/rust/issues/123461>.
+
+struct Unconstrained<T>(T);
+
+fn main() {
+    unsafe { std::mem::transmute::<_, ()>(|o_b: Unconstrained<_>| {}) };
+    //~^ ERROR type annotations needed
+    // We unfortunately don't check `Wf(Unconstrained<_>)`, so we won't
+    // hit an ambiguity error before checking the transmute. That means
+    // we still may have inference variables in our transmute src.
+}
diff --git a/tests/ui/transmute/ambiguity-in-closure-arg.stderr b/tests/ui/transmute/ambiguity-in-closure-arg.stderr
new file mode 100644
index 0000000000000..1b9140936bb12
--- /dev/null
+++ b/tests/ui/transmute/ambiguity-in-closure-arg.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/ambiguity-in-closure-arg.rs:6:14
+   |
+LL |     unsafe { std::mem::transmute::<_, ()>(|o_b: Unconstrained<_>| {}) };
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for fn item `unsafe extern "rust-intrinsic" fn({closure@$DIR/ambiguity-in-closure-arg.rs:6:43: 6:66}) {transmute::<{closure@$DIR/ambiguity-in-closure-arg.rs:6:43: 6:66}, ()>}`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0282`.