{"record":{"id":"2e921f93c8749c39","repo":"GyulyVGC/sniffnet","slug":"unknown-variant-other-expected-one-of-name","errorCode":null,"errorMessage":"unknown variant {other}, expected one of `Name`, `Unknown`, `NotApplicable`","messagePattern":"unknown variant (.+?), expected one of `Name`, `Unknown`, `NotApplicable`","errorType":"validation","errorClass":"serde::de::Error","httpStatus":null,"severity":"error","filePath":"src/networking/types/service.rs","lineNumber":49,"sourceCode":"            where\n                A: de::EnumAccess<'de>,\n            {\n                let (variant, access) = data.variant::<String>()?;\n                match variant.as_str() {\n                    \"Name\" => {\n                        let s: String = access.newtype_variant()?;\n                        let leaked: &'static str = Box::leak(s.into_boxed_str());\n                        Ok(Service::Name(leaked))\n                    }\n                    \"Unknown\" => {\n                        access.unit_variant()?;\n                        Ok(Service::Unknown)\n                    }\n                    \"NotApplicable\" => {\n                        access.unit_variant()?;\n                        Ok(Service::NotApplicable)\n                    }\n                    other => Err(de::Error::unknown_variant(\n                        other,\n                        &[\"Name\", \"Unknown\", \"NotApplicable\"],\n                    )),\n                }\n            }\n        }\n\n        deserializer.deserialize_enum(\n            \"Service\",\n            &[\"Name\", \"Unknown\", \"NotApplicable\"],\n            ServiceVisitor,\n        )\n    }\n}\n\nimpl Service {\n    pub fn to_string_with_equal_prefix(self) -> String {\n        format!(\"={self}\")","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/GyulyVGC/sniffnet/blob/48b0575dc0d3c7e503a466a3cb2c1466ba600f8e/src/networking/types/service.rs#L31-L67","documentation":"In the same manual Service deserializer (src/networking/types/service.rs:49), after reading the variant name, anything other than \"Name\", \"Unknown\", or \"NotApplicable\" raises de::Error::unknown_variant(other, &[\"Name\",\"Unknown\",\"NotApplicable\"]), surfacing as e.g. 'unknown variant `name`, expected one of `Name`, `Unknown`, `NotApplicable`'. This is the strict-variant gate for the leaked-string enum: the set of variants is fixed and case-sensitive.","triggerScenarios":"serde_json::from_str::<Service> on input whose enum tag is misspelled or new: `{\"name\":\"https\"}` (lowercase), `{\"NAME\":\"https\"}`, `{\"Known\":\"https\"}`, or a future/removed variant like `{\"Port\":443}`. Any string tag outside the three accepted names reaches the `other` arm and produces this error; the unit tests in service.rs (test_deserialize_invalid_variant) exercise exactly this path.","commonSituations":"Case mismatches from hand-written JSON or non-Rust producers (JavaScript camelCase); schema drift between a producer serialization of a different enum version and Sniffnet's fixed variant list; renaming variants in a fork without updating data files; pipelines writing the display name of the service ('HTTPS') instead of the variant tag.","solutions":["Use exactly one of the three tags with exact casing: \"Name\" (with a string payload), \"Unknown\", or \"NotApplicable\".","Fix casing in the source JSON: {\"name\":\"https\"} → {\"Name\":\"https\"}.","Before deserializing untrusted data, check the variant tag: parse to serde_json::Value and verify the key is one of the allowed set, mapping legacy/renamed tags explicitly.","If a genuinely new variant is needed, extend the enum and the match arms in service.rs (and its Serialize impl) together, then regenerate the data files."],"exampleFix":"// before — unknown/misspelled variant tag\nlet e = serde_json::from_str::<Service>(\"{\\\"name\\\":\\\"https\\\"}\");\n// Err: unknown variant `name`, expected one of `Name`, `Unknown`, `NotApplicable`\n\n// after — normalize the tag before parsing\nlet v: serde_json::Value = serde_json::from_str(raw)?;\nif let Some(tag) = v.as_object().and_then(|m| m.keys().next()) {\n    assert!(matches!(tag.as_str(), \"Name\" | \"Unknown\" | \"NotApplicable\"), \"bad tag {tag}\");\n}\nlet s: Service = serde_json::from_value(v)?; // {\"Name\":\"https\"} → Service::Name(\"https\")","handlingStrategy":"type-guard","validationCode":"// allow-list the variant tag before deserializing\nconst SERVICE_VARIANTS: [&str; 3] = [\"Name\", \"Unknown\", \"NotApplicable\"];\nfn variant_tag_ok(v: &serde_json::Value) -> bool {\n    match v {\n        serde_json::Value::String(s) => SERVICE_VARIANTS.contains(&s.as_str()),\n        serde_json::Value::Object(m) => m.len() == 1\n            && SERVICE_VARIANTS.contains(&m.keys().next().map(String::as_str).unwrap_or_default()),\n        _ => false,\n    }\n}","typeGuard":"fn is_known_service_variant(tag: &str) -> bool {\n    matches!(tag, \"Name\" | \"Unknown\" | \"NotApplicable\")\n}","tryCatchPattern":"// distinguish unknown-variant from other serde errors and recover with a default\nmatch serde_json::from_str::<Service>(raw) {\n    Ok(s) => s,\n    Err(e) if e.is_data() && e.to_string().starts_with(\"unknown variant\") => {\n        Service::Unknown // or log & reject: variant names are case-sensitive, fix the producer\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Match variant casing exactly: Name/Unknown/NotApplicable are capital-sensitive.","Beware camelCase producers (JavaScript) emitting {\"name\":...} — normalize tags before parsing.","When renaming or adding enum variants, regenerate all serialized data in lockstep.","Unit-test round-trips for every variant (as src/networking/types/service.rs tests do) so schema drift is caught in CI."],"tags":["rust","serde","deserialization","json","enum-variants","schema"],"backgroundTag":null,"analyzedSha":"48b0575dc0d3c7e503a466a3cb2c1466ba600f8e","analyzedAt":"2026-08-16T09:14:10.427Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}