Issue with serde flatten and optional member structs
⚓ Rust 📅 2026-02-12 👤 surdeus 👁️ 1Short description and MRE: when using #[serde(flatten)] on an optional member struct with nothing but optional members deserializes as a Some(Member { a: None }).
use serde::Deserialize;
use serde_with::skip_serializing_none;
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Deserialize)]
pub struct TopLevel {
#[serde(flatten)]
pub contained: Option<Contained>,
}
#[skip_serializing_none]
#[derive(Clone, Debug, Default, Deserialize)]
pub struct Contained {
pub optional: Option<String>,
}
fn main() {
let json = r#"{}"#;
let top: TopLevel = serde_json::from_str(&json).unwrap();
println!("{top:?}");
assert!(top.contained.is_none());
}
From the println!: TopLevel { contained: Some(Contained { optional: None }) }
Is there anything I can do to coax it into making it collapse that to a None?
Long description: I'm in the rather chaotic world of JOSE/JWT using member structs tagged with #[serde(flatten)] to be able to reuse rather than copy a lot of fields, usually with a type parameter for the field. Sometimes the collection of fields is rather large, so I wanted to tag them as optional, but that doesn't seem to work when I use flatten.
If there's a better technique I should be using, I'm all ears.
1 post - 1 participant
🏷️ Rust_feed