diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index b9e256236e9..bf3b72caeb4 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -41,7 +41,9 @@ mod trait_goals;
 
 pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt};
 pub use fulfill::FulfillmentCtxt;
-pub(crate) use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
+pub(crate) use normalize::{
+    deeply_normalize, deeply_normalize_for_diagnostics, deeply_normalize_with_skipped_universes,
+};
 
 #[derive(Debug, Clone, Copy)]
 enum SolverMode {
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index b0a34898570..ea512ba5fa7 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -4,12 +4,13 @@ use crate::traits::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::infer::at::At;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::TraitEngineExt;
 use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::traits::Reveal;
+use rustc_middle::traits::{ObligationCause, Reveal};
 use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex};
-use rustc_middle::ty::{FallibleTypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
 
 use super::FulfillmentCtxt;
@@ -230,3 +231,42 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
         }
     }
 }
+
+// Deeply normalize a value and return it
+pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
+    infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    t: T,
+) -> T {
+    t.fold_with(&mut DeeplyNormalizeForDiagnosticsFolder {
+        at: infcx.at(&ObligationCause::dummy(), param_env),
+    })
+}
+
+struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> {
+    at: At<'a, 'tcx>,
+}
+
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, 'tcx> {
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.at.infcx.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        deeply_normalize_with_skipped_universes(
+            self.at,
+            ty,
+            vec![None; ty.outer_exclusive_binder().as_usize()],
+        )
+        .unwrap_or_else(|_| ty.super_fold_with(self))
+    }
+
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        deeply_normalize_with_skipped_universes(
+            self.at,
+            ct,
+            vec![None; ct.outer_exclusive_binder().as_usize()],
+        )
+        .unwrap_or_else(|_| ct.super_fold_with(self))
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 8e2ec2e46b2..db4d4a93e54 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -6,8 +6,8 @@
 
 use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::InferOk;
-use crate::solve::inspect;
 use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
+use crate::solve::{deeply_normalize_for_diagnostics, inspect};
 use crate::traits::engine::TraitEngineExt;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs};
@@ -308,7 +308,13 @@ fn overlap<'tcx>(
         .iter()
         .any(|c| c.0.involves_placeholders());
 
-    let impl_header = selcx.infcx.resolve_vars_if_possible(impl1_header);
+    let mut impl_header = infcx.resolve_vars_if_possible(impl1_header);
+
+    // Deeply normalize the impl header for diagnostics, ignoring any errors if this fails.
+    if infcx.next_trait_solver() {
+        impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header);
+    }
+
     Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
 }
 
@@ -1084,6 +1090,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
                         Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
                         Ok(Err(conflict)) => {
                             if !trait_ref.references_error() {
+                                // Normalize the trait ref for diagnostics, ignoring any errors if this fails.
+                                let trait_ref =
+                                    deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
+
                                 let self_ty = trait_ref.self_ty();
                                 let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
                                 ambiguity_cause = Some(match conflict {
diff --git a/tests/ui/coherence/normalize-for-errors.current.stderr b/tests/ui/coherence/normalize-for-errors.current.stderr
new file mode 100644
index 00000000000..0e48aaed879
--- /dev/null
+++ b/tests/ui/coherence/normalize-for-errors.current.stderr
@@ -0,0 +1,14 @@
+error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, _)`
+  --> $DIR/normalize-for-errors.rs:16:1
+   |
+LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
+   | ------------------------------------------------------ first implementation here
+LL |
+LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, _)`
+   |
+   = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/coherence/normalize-for-errors.next.stderr b/tests/ui/coherence/normalize-for-errors.next.stderr
new file mode 100644
index 00000000000..a8a7d437b32
--- /dev/null
+++ b/tests/ui/coherence/normalize-for-errors.next.stderr
@@ -0,0 +1,14 @@
+error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, <_ as Iterator>::Item)`
+  --> $DIR/normalize-for-errors.rs:16:1
+   |
+LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
+   | ------------------------------------------------------ first implementation here
+LL |
+LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, <_ as Iterator>::Item)`
+   |
+   = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/coherence/normalize-for-errors.rs b/tests/ui/coherence/normalize-for-errors.rs
new file mode 100644
index 00000000000..367d34251ae
--- /dev/null
+++ b/tests/ui/coherence/normalize-for-errors.rs
@@ -0,0 +1,21 @@
+// revisions: current next
+//[next] compile-flags: -Ztrait-solver=next
+
+struct MyType;
+trait MyTrait<S> {}
+
+trait Mirror {
+    type Assoc;
+}
+impl<T> Mirror for T {
+    type Assoc = T;
+}
+
+impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
+//~^ NOTE first implementation here
+impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
+//~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>,
+//~| NOTE conflicting implementation for `(Box<(MyType,)>,
+//~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
+
+fn main() {}