diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs
index e1face32716..9b59e4968a3 100644
--- a/src/tools/compiletest/src/errors.rs
+++ b/src/tools/compiletest/src/errors.rs
@@ -3,7 +3,6 @@ use std::fs::File;
 use std::io::BufReader;
 use std::io::prelude::*;
 use std::path::Path;
-use std::str::FromStr;
 use std::sync::OnceLock;
 
 use regex::Regex;
@@ -18,30 +17,39 @@ pub enum ErrorKind {
     Warning,
 }
 
-impl FromStr for ErrorKind {
-    type Err = ();
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let s = s.to_uppercase();
-        let part0: &str = s.split(':').next().unwrap();
-        match part0 {
-            "HELP" => Ok(ErrorKind::Help),
-            "ERROR" => Ok(ErrorKind::Error),
-            "NOTE" => Ok(ErrorKind::Note),
-            "SUGGESTION" => Ok(ErrorKind::Suggestion),
-            "WARN" | "WARNING" => Ok(ErrorKind::Warning),
-            _ => Err(()),
+impl ErrorKind {
+    pub fn from_compiler_str(s: &str) -> ErrorKind {
+        match s {
+            "help" => ErrorKind::Help,
+            "error" | "error: internal compiler error" => ErrorKind::Error,
+            "note" | "failure-note" => ErrorKind::Note,
+            "warning" => ErrorKind::Warning,
+            _ => panic!("unexpected compiler diagnostic kind `{s}`"),
         }
     }
+
+    /// Either the canonical uppercase string, or some additional versions for compatibility.
+    /// FIXME: consider keeping only the canonical versions here.
+    fn from_user_str(s: &str) -> Option<ErrorKind> {
+        Some(match s {
+            "HELP" | "help" => ErrorKind::Help,
+            "ERROR" | "error" => ErrorKind::Error,
+            "NOTE" | "note" => ErrorKind::Note,
+            "SUGGESTION" => ErrorKind::Suggestion,
+            "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning,
+            _ => return None,
+        })
+    }
 }
 
 impl fmt::Display for ErrorKind {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
-            ErrorKind::Help => write!(f, "help message"),
-            ErrorKind::Error => write!(f, "error"),
-            ErrorKind::Note => write!(f, "note"),
-            ErrorKind::Suggestion => write!(f, "suggestion"),
-            ErrorKind::Warning => write!(f, "warning"),
+            ErrorKind::Help => write!(f, "HELP"),
+            ErrorKind::Error => write!(f, "ERROR"),
+            ErrorKind::Note => write!(f, "NOTE"),
+            ErrorKind::Suggestion => write!(f, "SUGGESTION"),
+            ErrorKind::Warning => write!(f, "WARN"),
         }
     }
 }
@@ -64,7 +72,7 @@ impl Error {
         use colored::Colorize;
         format!(
             "{: <10}line {: >3}: {}",
-            self.kind.map(|kind| kind.to_string()).unwrap_or_default().to_uppercase(),
+            self.kind.map(|kind| kind.to_string()).unwrap_or_default(),
             self.line_num_str(),
             self.msg.cyan(),
         )
@@ -154,18 +162,12 @@ fn parse_expected(
     }
 
     // Get the part of the comment after the sigil (e.g. `~^^` or ~|).
-    let whole_match = captures.get(0).unwrap();
-    let (_, mut msg) = line.split_at(whole_match.end());
-
-    let first_word = msg.split_whitespace().next().expect("Encountered unexpected empty comment");
-
-    // If we find `//~ ERROR foo` or something like that, skip the first word.
-    let kind = first_word.parse::<ErrorKind>().ok();
-    if kind.is_some() {
-        msg = &msg.trim_start().split_at(first_word.len()).1;
-    }
-
-    let msg = msg.trim().to_owned();
+    let tag = captures.get(0).unwrap();
+    let rest = line[tag.end()..].trim_start();
+    let (kind_str, _) = rest.split_once(|c: char| !c.is_ascii_alphabetic()).unwrap_or((rest, ""));
+    let kind = ErrorKind::from_user_str(kind_str);
+    let untrimmed_msg = if kind.is_some() { &rest[kind_str.len()..] } else { rest };
+    let msg = untrimmed_msg.strip_prefix(':').unwrap_or(untrimmed_msg).trim().to_owned();
 
     let line_num_adjust = &captures["adjust"];
     let (follow_prev, line_num) = if line_num_adjust == "|" {
@@ -181,7 +183,7 @@ fn parse_expected(
     debug!(
         "line={:?} tag={:?} follow_prev={:?} kind={:?} msg={:?}",
         line_num,
-        whole_match.as_str(),
+        tag.as_str(),
         follow_prev,
         kind,
         msg
diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs
index 2a6fcd6cf81..62fe538ee32 100644
--- a/src/tools/compiletest/src/json.rs
+++ b/src/tools/compiletest/src/json.rs
@@ -1,7 +1,6 @@
 //! These structs are a subset of the ones found in `rustc_errors::json`.
 
 use std::path::{Path, PathBuf};
-use std::str::FromStr;
 use std::sync::OnceLock;
 
 use regex::Regex;
@@ -230,7 +229,7 @@ fn push_actual_errors(
     // Convert multi-line messages into multiple errors.
     // We expect to replace these with something more structured anyhow.
     let mut message_lines = diagnostic.message.lines();
-    let kind = ErrorKind::from_str(&diagnostic.level).ok();
+    let kind = Some(ErrorKind::from_compiler_str(&diagnostic.level));
     let first_line = message_lines.next().unwrap_or(&diagnostic.message);
     if primary_spans.is_empty() {
         static RE: OnceLock<Regex> = OnceLock::new();
@@ -240,7 +239,8 @@ fn push_actual_errors(
             line_num: None,
             kind,
             msg: with_code(None, first_line),
-            require_annotation: !RE.get_or_init(re_init).is_match(first_line),
+            require_annotation: diagnostic.level != "failure-note"
+                && !RE.get_or_init(re_init).is_match(first_line),
         });
     } else {
         for span in primary_spans {
diff --git a/tests/ui/async-await/issue-70818.rs b/tests/ui/async-await/issue-70818.rs
index 36295a84e7a..bc181de8d92 100644
--- a/tests/ui/async-await/issue-70818.rs
+++ b/tests/ui/async-await/issue-70818.rs
@@ -2,7 +2,7 @@
 
 use std::future::Future;
 fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
-    //~^ Error future cannot be sent between threads safely
+    //~^ ERROR future cannot be sent between threads safely
     async { (ty, ty1) }
 }
 
diff --git a/tests/ui/async-await/issue-71137.rs b/tests/ui/async-await/issue-71137.rs
index 551cf85047c..6fbf17ccf0d 100644
--- a/tests/ui/async-await/issue-71137.rs
+++ b/tests/ui/async-await/issue-71137.rs
@@ -19,5 +19,5 @@ async fn wrong_mutex() {
 }
 
 fn main() {
-  fake_spawn(wrong_mutex()); //~ Error future cannot be sent between threads safely
+  fake_spawn(wrong_mutex()); //~ ERROR future cannot be sent between threads safely
 }
diff --git a/tests/ui/const-generics/defaults/mismatch.rs b/tests/ui/const-generics/defaults/mismatch.rs
index ec131505ed7..3e35c2060b1 100644
--- a/tests/ui/const-generics/defaults/mismatch.rs
+++ b/tests/ui/const-generics/defaults/mismatch.rs
@@ -5,18 +5,18 @@ pub struct Example4<const N: usize = 13, const M: usize = 4>;
 
 fn main() {
     let e: Example<13> = ();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     //~| expected struct `Example`
     let e: Example2<u32, 13> = ();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     //~| expected struct `Example2`
     let e: Example3<13, u32> = ();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     //~| expected struct `Example3`
     let e: Example3<7> = ();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     //~| expected struct `Example3<7>`
     let e: Example4<7> = ();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     //~| expected struct `Example4<7>`
 }
diff --git a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs
index 6c4ee1af210..e7f050dae36 100644
--- a/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs
+++ b/tests/ui/const-generics/dont-evaluate-array-len-on-err-1.rs
@@ -13,7 +13,7 @@ trait Foo {
         [Adt; std::mem::size_of::<Self::Assoc>()]: ,
     {
         <[Adt; std::mem::size_of::<Self::Assoc>()] as Foo>::bar()
-        //~^ Error: the trait bound
+        //~^ ERROR the trait bound
     }
 
     fn bar() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs b/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs
index 7561ae2febb..33872ce7f0f 100644
--- a/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs
+++ b/tests/ui/const-generics/generic_const_exprs/abstract-const-as-cast-3.rs
@@ -15,15 +15,15 @@ where
 
     // errors are bad but seems to be pre-existing issue #86198
     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
-    //~^ Error: mismatched types
-    //~^^ Error: unconstrained generic constant
+    //~^ ERROR mismatched types
+    //~^^ ERROR unconstrained generic constant
     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
-    //~^ Error: mismatched types
-    //~^^ Error: unconstrained generic constant
+    //~^ ERROR mismatched types
+    //~^^ ERROR unconstrained generic constant
     assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     assert_impl::<HasCastInTraitImpl<14, 13>>();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
 }
 pub fn use_trait_impl_2<const N: usize>()
 where
@@ -33,15 +33,15 @@ where
 
     // errors are bad but seems to be pre-existing issue #86198
     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
-    //~^ Error: mismatched types
-    //~^^ Error: unconstrained generic constant
+    //~^ ERROR mismatched types
+    //~^^ ERROR unconstrained generic constant
     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
-    //~^ Error: mismatched types
-    //~^^ Error: unconstrained generic constant
+    //~^ ERROR mismatched types
+    //~^^ ERROR unconstrained generic constant
     assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
     assert_impl::<HasCastInTraitImpl<14, 13>>();
-    //~^ Error: mismatched types
+    //~^ ERROR mismatched types
 }
 
 fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-72787.rs b/tests/ui/const-generics/generic_const_exprs/issue-72787.rs
index c3208786708..ea65b6d3fdf 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-72787.rs
+++ b/tests/ui/const-generics/generic_const_exprs/issue-72787.rs
@@ -9,8 +9,8 @@ pub trait True {}
 
 impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
     Condition<{ LHS <= RHS }>: True
-//[min]~^ Error generic parameters may not be used in const operations
-//[min]~| Error generic parameters may not be used in const operations
+//[min]~^ ERROR generic parameters may not be used in const operations
+//[min]~| ERROR generic parameters may not be used in const operations
 {
 }
 impl True for Condition<true> {}
@@ -21,8 +21,8 @@ where
     IsLessOrEqual<I, 8>: True,
     IsLessOrEqual<J, 8>: True,
     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
-//[min]~^ Error generic parameters may not be used in const operations
-//[min]~| Error generic parameters may not be used in const operations
+//[min]~^ ERROR generic parameters may not be used in const operations
+//[min]~| ERROR generic parameters may not be used in const operations
     // Condition<{ 8 - I <= 8 - J }>: True,
 {
     fn print() {
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs b/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs
index 2fa9a71fbb3..f08b9ceffb9 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs
+++ b/tests/ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs
@@ -14,7 +14,7 @@ trait Foo {
         [(); std::mem::size_of::<Self::Assoc>()]: ,
     {
         Self::AssocInstance == [(); std::mem::size_of::<Self::Assoc>()];
-        //~^ Error: mismatched types
+        //~^ ERROR mismatched types
     }
 }
 
diff --git a/tests/ui/impl-trait/impl-generic-mismatch.rs b/tests/ui/impl-trait/impl-generic-mismatch.rs
index fb8bde0d081..f05e01716c3 100644
--- a/tests/ui/impl-trait/impl-generic-mismatch.rs
+++ b/tests/ui/impl-trait/impl-generic-mismatch.rs
@@ -6,7 +6,7 @@ trait Foo {
 
 impl Foo for () {
     fn foo<U: Debug>(&self, _: &U) { }
-    //~^ Error method `foo` has incompatible signature for trait
+    //~^ ERROR method `foo` has incompatible signature for trait
 }
 
 trait Bar {
@@ -15,7 +15,7 @@ trait Bar {
 
 impl Bar for () {
     fn bar(&self, _: &impl Debug) { }
-    //~^ Error method `bar` has incompatible signature for trait
+    //~^ ERROR method `bar` has incompatible signature for trait
 }
 
 trait Baz {
@@ -24,7 +24,7 @@ trait Baz {
 
 impl Baz for () {
     fn baz<T: Debug>(&self, _: &impl Debug, _: &T) { }
-    //~^ Error method `baz` has incompatible signature for trait
+    //~^ ERROR method `baz` has incompatible signature for trait
 }
 
 // With non-local trait (#49841):
@@ -35,7 +35,7 @@ struct X;
 
 impl Hash for X {
     fn hash(&self, hasher: &mut impl Hasher) {}
-    //~^ Error method `hash` has incompatible signature for trait
+    //~^ ERROR method `hash` has incompatible signature for trait
 }
 
 fn main() {}
diff --git a/tests/ui/mismatched_types/assignment-operator-unimplemented.rs b/tests/ui/mismatched_types/assignment-operator-unimplemented.rs
index 21df464d5e4..04a379bbd04 100644
--- a/tests/ui/mismatched_types/assignment-operator-unimplemented.rs
+++ b/tests/ui/mismatched_types/assignment-operator-unimplemented.rs
@@ -3,5 +3,5 @@ struct Foo;
 fn main() {
   let mut a = Foo;
   let ref b = Foo;
-  a += *b; //~ Error: binary assignment operation `+=` cannot be applied to type `Foo`
+  a += *b; //~ ERROR binary assignment operation `+=` cannot be applied to type `Foo`
 }
diff --git a/tests/ui/modules/issue-107649.rs b/tests/ui/modules/issue-107649.rs
index af5758d7985..f93fb07e17a 100644
--- a/tests/ui/modules/issue-107649.rs
+++ b/tests/ui/modules/issue-107649.rs
@@ -102,5 +102,5 @@ fn main() {
     ();
     ();
     ();
-    dbg!(lib::Dummy); //~ Error: `Dummy` doesn't implement `Debug`
+    dbg!(lib::Dummy); //~ ERROR `Dummy` doesn't implement `Debug`
 }
diff --git a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs
index b23cb9ce917..73d173022f6 100644
--- a/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs
+++ b/tests/ui/parallel-rustc/cache-after-waiting-issue-111528.rs
@@ -10,7 +10,7 @@ pub fn a() {
 
 #[export_name="fail"]
 pub fn b() {
-//~^ Error symbol `fail` is already defined
+//~^ ERROR symbol `fail` is already defined
 }
 
 fn main() {}
diff --git a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs
index ecd3f588119..7216b0294dc 100644
--- a/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs
+++ b/tests/ui/resolve/typo-suggestion-for-variable-with-name-similar-to-struct-field.rs
@@ -4,15 +4,15 @@ struct A {
 
 impl A {
     fn new(cofig: String) -> Self {
-        Self { config } //~ Error cannot find value `config` in this scope
+        Self { config } //~ ERROR cannot find value `config` in this scope
     }
 
     fn do_something(cofig: String) {
-        println!("{config}"); //~ Error cannot find value `config` in this scope
+        println!("{config}"); //~ ERROR cannot find value `config` in this scope
     }
 
     fn self_is_available(self, cofig: String) {
-        println!("{config}"); //~ Error cannot find value `config` in this scope
+        println!("{config}"); //~ ERROR cannot find value `config` in this scope
     }
 }
 
diff --git a/tests/ui/suggestions/issue-103646.rs b/tests/ui/suggestions/issue-103646.rs
index f679640c5dc..d8b06d663af 100644
--- a/tests/ui/suggestions/issue-103646.rs
+++ b/tests/ui/suggestions/issue-103646.rs
@@ -5,7 +5,7 @@ trait Cat {
 fn uwu<T: Cat>(c: T) {
     c.nya();
     //~^ ERROR no method named `nya` found for type parameter `T` in the current scope
-    //~| Suggestion T::nya()
+    //~| SUGGESTION T::nya()
 }
 
 fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/issue-53598.rs b/tests/ui/type-alias-impl-trait/issue-53598.rs
index 3262c69cf5a..d8eee3218ed 100644
--- a/tests/ui/type-alias-impl-trait/issue-53598.rs
+++ b/tests/ui/type-alias-impl-trait/issue-53598.rs
@@ -17,7 +17,7 @@ impl Foo for S2 {
     type Item = impl Debug;
 
     fn foo<T: Debug>(_: T) -> Self::Item {
-        //~^ Error type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
+        //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
         S::<T>(Default::default())
     }
 }