Enum with #[serde(untagged)] Specification or Bug

use serde::Serialize;
use serde::Deserialize;

#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(untagged)]
pub enum TestResponse {
    Unavailable { status: String },
    Error { status: String },
}


fn main() {
    
    let given = TestResponse::Error {
        status: String::from("There is an error"),
    };
    
    println!("Given: {:?}", given);
    
    let serialized = serde_json::to_string(&given).unwrap();
    println!("Serialize: {}", serialized);
    
    let deserialized: TestResponse = serde_json::from_str(serialized.as_str()).unwrap();
    println!("Deserialize: {:?}", deserialized);
    
    assert_eq!(given, deserialized);
    
}

(Playground)

Output:

Given: Error { status: "There is an error" }
Serialize: {"status":"There is an error"}
Deserialize: Unavailable { status: "There is an error" }

Errors:

   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 0.76s
     Running `target/debug/playground`
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `Error { status: "There is an error" }`,
 right: `Unavailable { status: "There is an error" }`', src/main.rs:26:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

My expectation should be the same with the given but Instead of Error, it chooses the Unavailable enum field. Is this a bug?

https://serde.rs/enum-representations.html#untagged

There is no explicit tag identifying which variant the data contains. Serde will try to match the data against each variant in order and the first one that deserializes successfully is the one returned.

3 Likes

Thank for the explanation. I see now clearly what happened.

If there is no type/variant tag, and the structure of the two variants is exactly the same, then how could the deserializer possibly differentiate between them? The information you are expecting it to use simply isn't there.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.