GyulyVGC/sniffnet · error · serde::de::Error

a Service enum

Error message

a Service enum

What it means

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.

Source

Thrown at src/networking/types/service.rs:27

    /// Not identified
    #[default]
    Unknown,
    /// Not applicable
    NotApplicable,
}

impl<'de> Deserialize<'de> for Service {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct ServiceVisitor;

        impl<'de> de::Visitor<'de> for ServiceVisitor {
            type Value = Service;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                formatter.write_str("a Service enum")
            }

            fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
            where
                A: de::EnumAccess<'de>,
            {
                let (variant, access) = data.variant::<String>()?;
                match variant.as_str() {
                    "Name" => {
                        let s: String = access.newtype_variant()?;
                        let leaked: &'static str = Box::leak(s.into_boxed_str());
                        Ok(Service::Name(leaked))
                    }
                    "Unknown" => {
                        access.unit_variant()?;
                        Ok(Service::Unknown)
                    }
                    "NotApplicable" => {

View on GitHub (pinned to 48b0575dc0)

Solutions

  1. Emit the enum in serde's externally tagged form: known service as object {"Name":"https"}, the others as bare strings "Unknown" / "NotApplicable".
  2. Round-trip via Service's own Serialize to learn the exact accepted shape: serde_json::to_string(&Service::Name("https")) → {"Name":"https"}.
  3. Validate upstream JSON against that shape (JSON Schema or a pre-parse check) before from_str.
  4. If you control both ends and want untagged strings, deserialize into a String/serde_json::Value first and map to Service manually.

Example fix

// before — wrong shape: bare string payload where enum expected
let s: Service = serde_json::from_str("\"https\"")?; // invalid type: expected a Service enum

// after — serde's externally tagged enum representation
let s: Service = serde_json::from_str("{\"Name\":\"https\"}")?;      // Service::Name("https")
let u: Service = serde_json::from_str("\"Unknown\"")?;              // Service::Unknown
let n: Service = serde_json::from_str("\"NotApplicable\"")?;        // Service::NotApplicable
Defensive patterns

Strategy: type-guard

Validate before calling

// shape-check raw JSON before parsing into Service
fn service_shape_ok(v: &serde_json::Value) -> bool {
    match v {
        serde_json::Value::String(s) => matches!(s.as_str(), "Unknown" | "NotApplicable"),
        serde_json::Value::Object(m) => m.len() == 1 && m.get("Name").is_some_and(|n| n.is_string()),
        _ => false,
    }
}

Type guard

fn is_service_shaped(v: &serde_json::Value) -> bool {
    match v {
        serde_json::Value::String(s) => matches!(s.as_str(), "Unknown" | "NotApplicable"),
        serde_json::Value::Object(m) => {
            m.len() == 1 && matches!(m.keys().next().map(String::as_str), Some("Name"))
                && m["Name"].is_string()
        }
        _ => false,
    }
}

Try / catch

// catch shape errors with position context
match serde_json::from_str::<Service>(raw) {
    Ok(s) => Ok(s),
    Err(e) if e.to_string().contains("expected a Service enum") => {
        Err(format!("bad Service shape at {}: {raw}", e))
    }
    Err(e) => Err(e.to_string()),
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of GyulyVGC/sniffnet@48b0575dc0 (2026-08-16). Data as JSON: /api/errors/5892365b4bf05b96. Report an issue: GitHub.