{"record":{"id":"5892365b4bf05b96","repo":"GyulyVGC/sniffnet","slug":"a-service-enum","errorCode":null,"errorMessage":"a Service enum","messagePattern":"a Service enum","errorType":"validation","errorClass":"serde::de::Error","httpStatus":null,"severity":"error","filePath":"src/networking/types/service.rs","lineNumber":27,"sourceCode":"    /// Not identified\n    #[default]\n    Unknown,\n    /// Not applicable\n    NotApplicable,\n}\n\nimpl<'de> Deserialize<'de> for Service {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        struct ServiceVisitor;\n\n        impl<'de> de::Visitor<'de> for ServiceVisitor {\n            type Value = Service;\n\n            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {\n                formatter.write_str(\"a Service enum\")\n            }\n\n            fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>\n            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\" => {","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/GyulyVGC/sniffnet/blob/48b0575dc0d3c7e503a466a3cb2c1466ba600f8e/src/networking/types/service.rs#L9-L45","documentation":"The custom Deserialize impl for the Service enum (src/networking/types/service.rs:27) implements expecting() with the text 'a Service enum'. Serde invokes this message whenever the deserializer encounters input of the wrong shape — e.g. a JSON string, number, or map where an enum (\"Name\", \"Unknown\", \"NotApplicable\" variants) is required — producing errors like 'invalid type: string \"https\", expected a Service enum'. The manual impl exists to Box::leak the Name payload into a &'static str for cheap storage.","triggerScenarios":"Deserializing (serde_json::from_str::<Service> or any format driven by the Deserialize impl) data whose JSON shape is not an enum representation of Service: `\"https\"` (bare string) instead of `{\"Name\":\"https\"}` / `\"Name\"`-style tagged values, `42`, `null`, `{\"Name\":123}` (non-string payload), or a map with multiple entries where a newtype variant is expected.","commonSituations":"Hand-edited or machine-generated JSON consumed by tooling built on Sniffnet's types (e.g. analysis output, reports) where the service field was serialized differently than Sniffnet's Serialize derives (externally tagged enum: {\"Name\":\"https\"}, \"Unknown\", \"NotApplicable\"); version changes that altered the wire shape; feeding an array of strings from another tool into a field typed Service.","solutions":["Emit the enum in serde's externally tagged form: known service as object {\"Name\":\"https\"}, the others as bare strings \"Unknown\" / \"NotApplicable\".","Round-trip via Service's own Serialize to learn the exact accepted shape: serde_json::to_string(&Service::Name(\"https\")) → {\"Name\":\"https\"}.","Validate upstream JSON against that shape (JSON Schema or a pre-parse check) before from_str.","If you control both ends and want untagged strings, deserialize into a String/serde_json::Value first and map to Service manually."],"exampleFix":"// before — wrong shape: bare string payload where enum expected\nlet s: Service = serde_json::from_str(\"\\\"https\\\"\")?; // invalid type: expected a Service enum\n\n// after — serde's externally tagged enum representation\nlet s: Service = serde_json::from_str(\"{\\\"Name\\\":\\\"https\\\"}\")?;      // Service::Name(\"https\")\nlet u: Service = serde_json::from_str(\"\\\"Unknown\\\"\")?;              // Service::Unknown\nlet n: Service = serde_json::from_str(\"\\\"NotApplicable\\\"\")?;        // Service::NotApplicable","handlingStrategy":"type-guard","validationCode":"// shape-check raw JSON before parsing into Service\nfn service_shape_ok(v: &serde_json::Value) -> bool {\n    match v {\n        serde_json::Value::String(s) => matches!(s.as_str(), \"Unknown\" | \"NotApplicable\"),\n        serde_json::Value::Object(m) => m.len() == 1 && m.get(\"Name\").is_some_and(|n| n.is_string()),\n        _ => false,\n    }\n}","typeGuard":"fn is_service_shaped(v: &serde_json::Value) -> bool {\n    match v {\n        serde_json::Value::String(s) => matches!(s.as_str(), \"Unknown\" | \"NotApplicable\"),\n        serde_json::Value::Object(m) => {\n            m.len() == 1 && matches!(m.keys().next().map(String::as_str), Some(\"Name\"))\n                && m[\"Name\"].is_string()\n        }\n        _ => false,\n    }\n}","tryCatchPattern":"// catch shape errors with position context\nmatch serde_json::from_str::<Service>(raw) {\n    Ok(s) => Ok(s),\n    Err(e) if e.to_string().contains(\"expected a Service enum\") => {\n        Err(format!(\"bad Service shape at {}: {raw}\", e))\n    }\n    Err(e) => Err(e.to_string()),\n}","preventionTips":["Learn the accepted wire form by round-tripping: serde_json::to_string(&Service::Name(\"https\")) → {\"Name\":\"https\"}.","Generate producer JSON with Service's own Serialize instead of hand-writing shapes.","Validate payloads with a JSON Schema (or the type guard above) before deserializing.","Keep serialized data and enum definition in the same version of the codebase."],"tags":["rust","serde","deserialization","json","type-mismatch"],"backgroundTag":null,"analyzedSha":"48b0575dc0d3c7e503a466a3cb2c1466ba600f8e","analyzedAt":"2026-08-16T09:14:10.427Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}