Repository: serenity-rs/serenity (language: rust)

Issue:
Invalid Type Error
Iterating over all the messages in a server yields me an invalid type error every time. The error is:
`invalid type: string "#d0334d", expected u32 at line 1 column 123537`
I don't really know what to do in order to help debug this but I assume this is a deserialization error.
Branch: `current`


Discussion / hints:
This is most likely caused by #2882 missing `deserialize_with = "discord_colours"` for `MessageReaction::burst_colours`. Can you confirm @jamesbt365?
Ok I am testing rn with
```
#[serde(rename = "burst_colors", deserialize_with = "discord_colours")]
pub burst_colours: Option<Vec<Colour>>,
```
in message.rs and I will report back if that fixes it :)
> This is most likely caused by #2882 missing `deserialize_with = "discord_colours"` for `MessageReaction::burst_colours`. Can you confirm @jamesbt365?

I did miss rename on that one, so I'm almost certain its needed here too. will investigate shortly and open a PR for it.

Fix patch:
diff --git a/src/model/channel/message.rs b/src/model/channel/message.rs
index 9e3d15f2988..eb74c19c61d 100644
--- a/src/model/channel/message.rs
+++ b/src/model/channel/message.rs
@@ -22,7 +22,7 @@ use crate::gateway::ShardMessenger;
 #[cfg(feature = "model")]
 use crate::http::{CacheHttp, Http};
 use crate::model::prelude::*;
-use crate::model::utils::StrOrInt;
+use crate::model::utils::{discord_colours, StrOrInt};
 #[cfg(all(feature = "model", feature = "cache"))]
 use crate::utils;
 
@@ -947,7 +947,7 @@ pub struct MessageReaction {
     #[serde(rename = "emoji")]
     pub reaction_type: ReactionType,
     // The colours used for super reactions.
-    #[serde(rename = "burst_colors")]
+    #[serde(rename = "burst_colors", deserialize_with = "discord_colours")]
     pub burst_colours: Vec<Colour>,
 }
 
diff --git a/src/model/channel/reaction.rs b/src/model/channel/reaction.rs
index d63e1eb3a44..d0cc503db07 100644
--- a/src/model/channel/reaction.rs
+++ b/src/model/channel/reaction.rs
@@ -8,7 +8,6 @@ use std::str::FromStr;
 use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
 use serde::de::Error as DeError;
 use serde::ser::{Serialize, SerializeMap, Serializer};
-use serde_cow::CowStr;
 #[cfg(feature = "model")]
 use tracing::warn;
 
@@ -16,6 +15,7 @@ use tracing::warn;
 use crate::http::{CacheHttp, Http};
 use crate::internal::prelude::*;
 use crate::model::prelude::*;
+use crate::model::utils::discord_colours_opt;
 
 /// An emoji reaction to a message.
 ///
@@ -51,7 +51,7 @@ pub struct Reaction {
     /// Colours used for the super reaction animation.
     ///
     /// Only present on the ReactionAdd gateway event.
-    #[serde(rename = "burst_colors", default, deserialize_with = "discord_colours")]
+    #[serde(rename = "burst_colors", default, deserialize_with = "discord_colours_opt")]
     pub burst_colours: Option<Vec<Colour>>,
     /// The type of reaction.
     #[serde(rename = "type")]
@@ -88,40 +88,6 @@ impl Serialize for Reaction {
     }
 }
 
-fn discord_colours<'de, D>(deserializer: D) -> Result<Option<Vec<Colour>>, D::Error>
-where
-    D: Deserializer<'de>,
-{
-    let vec_str: Option<Vec<CowStr<'_>>> = Deserialize::deserialize(deserializer)?;
-
-    let Some(vec_str) = vec_str else { return Ok(None) };
-
-    if vec_str.is_empty() {
-        return Ok(None);
-    }
-
-    let colours: Result<Vec<_>, _> = vec_str
-        .iter()
-        .map(|s| {
-            let s = s.0.strip_prefix('#').ok_or_else(|| DeError::custom("Invalid colour data"))?;
-
-            if s.len() != 6 {
-                return Err(DeError::custom("Invalid colour data length"));
-            }
-
-            match u32::from_str_radix(s, 16) {
-                Ok(c) => Ok(Colour::new(c)),
-                Err(_) => Err(DeError::custom("Invalid colour data")),
-            }
-        })
-        .collect();
-
-    match colours {
-        Ok(colours) => Ok(Some(colours)),
-        Err(err) => Err(err),
-    }
-}
-
 #[cfg(feature = "model")]
 impl Reaction {
     /// Retrieves the associated the reaction was made in.
diff --git a/src/model/utils.rs b/src/model/utils.rs
index 639baf4118c..df900080bf0 100644
--- a/src/model/utils.rs
+++ b/src/model/utils.rs
@@ -4,7 +4,9 @@ use std::hash::Hash;
 use std::marker::PhantomData;
 use std::num::NonZeroU64;
 
+use serde::de::Error as DeError;
 use serde::ser::{Serialize, SerializeSeq, Serializer};
+use serde_cow::CowStr;
 
 use super::prelude::*;
 
@@ -426,3 +428,47 @@ where
         Ok(map)
     }
 }
+
+pub fn discord_colours_opt<'de, D>(deserializer: D) -> Result<Option<Vec<Colour>>, D::Error>
+where
+    D: Deserializer<'de>,
+{
+    let vec_str: Option<Vec<CowStr<'_>>> = Deserialize::deserialize(deserializer)?;
+
+    let Some(vec_str) = vec_str else { return Ok(None) };
+
+    if vec_str.is_empty() {
+        return Ok(None);
+    }
+
+    deserialize_colours::<D>(vec_str).map(Some)
+}
+
+pub fn discord_colours<'de, D>(deserializer: D) -> Result<Vec<Colour>, D::Error>
+where
+    D: Deserializer<'de>,
+{
+    let vec_str: Vec<CowStr<'_>> = Deserialize::deserialize(deserializer)?;
+
+    deserialize_colours::<D>(vec_str)
+}
+
+fn deserialize_colours<'de, D>(vec_str: Vec<CowStr<'_>>) -> Result<Vec<Colour>, D::Error>
+where
+    D: Deserializer<'de>,
+{
+    vec_str
+        .into_iter()
+        .map(|s| {
+            let s = s.0.strip_prefix('#').ok_or_else(|| DeError::custom("Invalid colour data"))?;
+
+            if s.len() != 6 {
+                return Err(DeError::custom("Invalid colour data length"));
+            }
+
+            u32::from_str_radix(s, 16)
+                .map(Colour::new)
+                .map_err(|_| DeError::custom("Invalid colour data"))
+        })
+        .collect()
+}


Test patch: