{"id":1182,"hash":"5f1d1c10d59ce1fcfb2dff5c5fd2fab68cb048a2dc1d51416df92e3710138709","pattern":"How can I use Serde with a JSON array with different objects for successes and errors?","full_message":"I want to use Serde to create an array with error messages as well as proper objects:\n\nextern crate serde; // 1.0.70\n#[macro_use]\nextern crate serde_derive; // 1.0.70\nextern crate serde_json; // 1.0.24\n\n#[derive(Serialize, Deserialize, Debug)]\npub struct MyError {\n    error: String,\n}\n\n#[derive(Serialize, Deserialize, Debug)]\npub struct MyAge {\n    age: i32,\n    name: String,\n}\n\nfn get_results(ages: Vec<i32>) -> Vec<MyAge> {\n    let mut results = vec![];\n    for age in ages {\n        if age < 100 && age > 0 {\n            results.push(MyAge {\n                age: age,\n                name: String::from(\"The dude\"),\n            });\n        } else {\n            results.push(MyError {\n                error: String::from(format!(\"{} is invalid age\", age)),\n            });\n        }\n    }\n    results\n}\n\nWhen I pass in the Vec [1, -6, 7] I want to serialize to the JSON:\n\n[{\"age\": 1, \"name\": \"The dude\"},{\"error\": \"-6 is invalid age\"},{\"age\": 7, \"name\": \"The dude\"}]\n\nHow do I do that? Knowing how to deserialize such an array would be nice as well.","ecosystem":"cargo","package_name":"json","package_version":null,"solution":"Here's one way of doing that:\n\n#[macro_use]\nextern crate serde_derive; // 1.0.117\nextern crate serde; // 1.0.117\nextern crate serde_json; // 1.0.59\n\n#[derive(Serialize, Deserialize, Debug)]\npub struct MyError {\n    error: String,\n}\n\n#[derive(Serialize, Deserialize, Debug)]\npub struct MyAge {\n    age: i32,\n    name: String,\n}\n\n#[derive(Debug)]\nenum AgeOrError {\n    Age(MyAge),\n    Error(MyError),\n}\n\nimpl serde::Serialize for AgeOrError {\n    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {\n        match self {\n            &AgeOrError::Age(ref my_age) => serializer.serialize_some(my_age),\n            &AgeOrError::Error(ref my_error) => serializer.serialize_some(my_error),\n        }\n    }\n}\n\nenum AgeOrErrorField {\n    Age,\n    Name,\n    Error,\n}\n\nimpl<'de> serde::Deserialize<'de> for AgeOrErrorField {\n    fn deserialize<D>(deserializer: D) -> Result<AgeOrErrorField, D::Error>\n    where\n        D: serde::Deserializer<'de>,\n    {\n        struct AgeOrErrorFieldVisitor;\n\n        impl<'de> serde::de::Visitor<'de> for AgeOrErrorFieldVisitor {\n            type Value = AgeOrErrorField;\n\n            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {\n                write!(formatter, \"age or error\")\n            }\n\n            fn visit_str<E>(self, value: &str) -> Result<AgeOrErrorField, E>\n            where\n                E: serde::de::Error,\n            {\n                Ok(match value {\n                    \"age\" => AgeOrErrorField::Age,\n                    \"name\" => AgeOrErrorField::Name,\n                    \"error\" => AgeOrErrorField::Error,\n                    _ => panic!(\"Unexpected field name: {}\", value),\n                })\n            }\n        }\n\n        deserializer.deserialize_any(AgeOrErrorFieldVisitor)\n    }\n}\n\nimpl<'de> serde::Deserialize<'de> for AgeOrError {\n    fn deserialize<D>(deserializer: D) -> Result<AgeOrError, D::Error>\n    where\n        D: serde::Deserializer<'de>,\n    {\n        deserializer.deserialize_map(AgeOrErrorVisitor)\n    }\n}\n\nstruct AgeOrErrorVisitor;\n\nimpl<'de> serde::de::Visitor<'de> for AgeOrErrorVisitor {\n    type Value = AgeOrError;\n\n    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {\n        write!(formatter, \"age or error\")\n    }\n\n    fn visit_map<A>(self, mut map: A) -> Result<AgeOrError, A::Error>\n    where\n        A: serde::de::MapAccess<'de>,\n    {\n        let mut age: Option<i32> = None;\n        let mut name: Option<String> = None;\n        let mut error: Option<String> = None;\n        loop {\n            match map.next_key()? {\n                Some(AgeOrErrorField::Age) => age = map.next_value()?,\n                Some(AgeOrErrorField::Name) => name = map.next_value()?,\n                Some(AgeOrErrorField::Error) => error = map.next_value()?,\n                None => break,\n            }\n        }\n        if let Some(error) = error {\n            Ok(AgeOrError::Error(MyError { error: error }))\n        } else {\n            Ok(AgeOrError::Age(MyAge {\n                age: age.expect(\"!age\"),\n                name: name.expect(\"!name\"),\n            }))\n        }\n    }\n}\n\nfn get_results(ages: &[i32]) -> Vec<AgeOrError> {\n    let mut results = Vec::with_capacity(ages.len());\n    for &age in ages.iter() {\n        if age < 100 && age > 0 {\n            results.push(AgeOrError::Age(MyAge {\n                age: age,\n                name: String::from(\"The dude\"),\n            }));\n        } else {\n            results.push(AgeOrError::Error(MyError {\n                error: format!(\"{} is invalid age\", age),\n            }));\n        }\n    }\n    results\n}\n\nfn main() {\n    let v = get_results(&[1, -6, 7]);\n    let serialized = serde_json::to_string(&v).expect(\"Can't serialize\");\n    println!(\"serialized: {}\", serialized);\n    let deserialized: Vec<AgeOrError> =\n        serde_json::from_str(&serialized).expect(\"Can't deserialize\");\n    println!(\"deserialized: {:?}\", deserialized);\n}\n\nNote that in deserialization we can't reuse the automatically generated deserializers because:\n\ndeserialization is kind of streaming the fields to us, we can't peek into the stringified JSON representation and guess what it is;\n\nwe don't have access to the serde::de::Visitor implementations that Serde generates.\n\nAlso I did a shortcut and panicked on errors. In production code you'd want to return the proper Serde errors instead.\n\nAnother solution would be to make a merged structure with all fields optional, like this:\n\n#[macro_use]\nextern crate serde_derive; // 1.0.70\nextern crate serde; // 1.0.70\nextern crate serde_json; // 1.0.24\n\n#[derive(Debug)]\npub struct MyError {\n    error: String,\n}\n\n#[derive(Debug)]\npub struct MyAge {\n    age: i32,\n    name: String,\n}\n\n#[derive(Serialize, Deserialize, Debug)]\npub struct MyAgeOrError {\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    age: Option<i32>,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    name: Option<String>,\n    #[serde(skip_serializing_if = \"Option::is_none\")]\n    error: Option<String>,\n}\n\nimpl MyAgeOrError {\n    fn from_age(age: MyAge) -> MyAgeOrError {\n        MyAgeOrError {\n            age: Some(age.age),\n            name: Some(age.name),\n            error: None,\n        }\n    }\n    fn from_error(error: MyError) -> MyAgeOrError {\n        MyAgeOrError {\n            age: None,\n            name: None,\n            error: Some(error.error),\n        }\n    }\n}\n\nfn get_results(ages: &[i32]) -> Vec<MyAgeOrError> {\n    let mut results = Vec::with_capacity(ages.len());\n    for &age in ages.iter() {\n        if age < 100 && age > 0 {\n            results.push(MyAgeOrError::from_age(MyAge {\n                age: age,\n                name: String::from(\"The dude\"),\n            }));\n        } else {\n            results.push(MyAgeOrError::from_error(MyError {\n                error: format!(\"{} is invalid age\", age),\n            }));\n        }\n    }\n    results\n}\n\nfn main() {\n    let v = get_results(&[1, -6, 7]);\n    let serialized = serde_json::to_string(&v).expect(\"Can't serialize\");\n    println!(\"serialized: {}\", serialized);\n    let deserialized: Vec<MyAgeOrError> =\n        serde_json::from_str(&serialized).expect(\"Can't deserialize\");\n    println!(\"deserialized: {:?}\", deserialized);\n}\n\nI'd vouch for this one because it allows the Rust structure (e.g. MyAgeOrError) to match the layout of your JSON. That way the JSON layout becomes documented in the Rust code.\n\nP.S. Lately I tend to delay the decoding of optional or dynamically typed JSON parts with the help of RawValue. It's tricky to serialize them though, because RawValue is a borrow. For instance, and to help with serialization, one can intern a RawValue, promoting it to the 'static lifetime:\n\nuse serde_json::value::{RawValue as RawJson};\n\nfn intern_raw_json(raw_json: Box<RawJson>) -> &'static RawJson {\n    use parking_lot::Mutex;\n    use std::mem::transmute;\n\n    static BUF: Mutex<Vec<Pin<Box<RawJson>>>> = Mutex::new(Vec::new());\n\n    let buf = BUF.lock();\n    let raw_json: Pin<Box<RawJson>> = raw_json.into();\n    let pt: &'static RawJson = {\n        let pt: &RawJson = &*raw_json;\n        transmute(pt)\n    };\n    buf.push(raw_json);\n    pt\n}\n\nIf performance is not an issue, then one can deserialize the dynamic parts into the Value.\n\nSimilarly, if using Value is an option, then custom deserialization can be simplified by implementing TryFrom<Value>.","confidence":0.95,"source":"stackoverflow","source_url":"https://stackoverflow.com/questions/37561593/how-can-i-use-serde-with-a-json-array-with-different-objects-for-successes-and-e","votes":12,"created_at":"2026-04-19T04:52:32.441929+00:00","updated_at":"2026-04-19T04:52:32.441929+00:00"}