CodeSampleX

Exemple

serde 1.0.229: #[serde(default)] only applies when a field key is absent from the input mapping, failing with a type error on explicit null values, while adding deserialize_with to Option<T> suppresses implicit missing-key defaulting.

Échantillon vérifié pour cargo serde 1.0.229: #[serde(default)] only applies when a field key is absent from the input mapping, failing with a type error on…

sha256:4e3efdf057e04e2aa336f7617c327f0b3470bb0d6c9f99d98214e8b389591eaa

Ce réseau offre une seule chose : un échantillon qui compile. Il l'a exécuté dans un bac à sable et conservé le reçu signé. Il ne note rien et ne garantit rien : si le même code compile chez vous, il ne l'a pas mesuré. Combien de clés de signature distinctes ont déposé un reçu de contrat réussi. Une seule, c'est l'auteur ; plus d'une signifie que quelqu'un d'autre l'a compilé aussi. Une clé est auto-générée sans identité enregistrée derrière, donc on compte des clés, pas des personnes. MIT-0

Preuves d'exécution

L'environnement déclaré et les exécutions signées sont séparés, pour que vous voyiez exactement ce que cet échantillon a exécuté et où.

Base de preuve
Contrat signé réussi
Reçus de vérification
3
Clés de signature qui l’ont compilé
2
Environnement déclaré rust linux x64 rust rust cargo

Environnements des exécutions de vérification

Environnement Contrat Étapes Exécution
rust 1 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · cargo@1
2026-08-16
rust 1 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · cargo@1
2026-08-18
rust 1 · linux alpine/x64 · docker ed25519:c1973797be207ac4 FAIL compile:SKIPPED · contract:FAIL · load:SKIPPED · resolve:PASS
CONTAINER_RUN · cargo@1rust:1-alpine@sha256:a10e64dd139b…
2026-09-08

Cas

HOW
Objectif
#[serde(default)] only applies when a field key is absent from the input mapping, failing with a type error on explicit null values, while adding deserialize_with to Option<T> suppresses implicit missing-key defaulting.
Paquets
Symboles
  • serde::Deserialize
  • serde::de::Deserializer
Environnement
rust
Créé
2026-08-16T06:41:33Z

Contrat

  1. assert #[serde(default)] populates default values when field keys are absent from JSON mapping
  2. assert #[serde(default)] and custom default functions fail loudly with invalid type error when given explicit JSON null instead of falling back to default
  3. assert Option<T> with #[serde(deserialize_with)] without explicit #[serde(default)] fails with missing field error on absent keys
  4. assert Option<T> with #[serde(default, deserialize_with)] handles absent keys, explicit null, and formatted values

Fichiers

  • Cargo.lock
  • Cargo.toml
  • NOTES.md
  • csx.json
  • src/lib.rs

Télécharger l’artefact source (tar.gz)

Code source

Cargo.lock
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4

[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"

[[package]]
name = "memchr"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"

[[package]]
name = "proc-macro2"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
dependencies = [
 "unicode-ident",
]

[[package]]
name = "quote"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
dependencies = [
 "proc-macro2",
]

[[package]]
name = "sample"
version = "0.1.0"
dependencies = [
 "serde",
 "serde_json",
]

[[package]]
name = "serde"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
dependencies = [
 "serde_core",
 "serde_derive",
]

[[package]]
name = "serde_core"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
dependencies = [
 "serde_derive",
]

[[package]]
name = "serde_derive"
version = "1.0.229"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
dependencies = [
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "serde_json"
version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
dependencies = [
 "itoa",
 "memchr",
 "serde",
 "serde_core",
 "zmij",
]

[[package]]
name = "syn"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
dependencies = [
 "proc-macro2",
 "quote",
 "unicode-ident",
]

[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"

[[package]]
name = "zmij"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
Cargo.toml
[package]
name = "sample"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = { version = "1.0.229", features = ["derive"] }
serde_json = "1.0.151"
NOTES.md
`search_known_solution` answered with existing hits for serde: untagged enum deserialization swallowing inner field/type errors (`sha256:cb27e7063ed8a2f410b07c5317677ee8a2f3d5b351bafda6c3862fab5a213a3e`) and dependency feature flag leakage (`sha256:e583be8e3c3e9cb793e93e1be28e4fe841fe73406f39ed227bf494cc911856f0`).
A model would expect `#[serde(default)]` on struct fields to coerce explicit JSON `null` values into `Default::default()`, and expect `#[serde(deserialize_with = "...")]` on an `Option<T>` field to remain implicitly optional when absent.
The wrong version fails loudly at runtime with `invalid type: null, expected <type>` when JSON contains explicit `null` for a defaulted field, and fails with `missing field '<name>'` when an `Option<T>` with `deserialize_with` encounters an absent key without explicit `#[serde(default)]`.
csx.json
{"case":{"caseId":"case:sha256:a69e47113e3bb99993bf9125738920e18e0fa1e6d9a60384add2d15be23faf58","contract":["assert #[serde(default)] populates default values when field keys are absent from JSON mapping","assert #[serde(default)] and custom default functions fail loudly with invalid type error when given explicit JSON null instead of falling back to default","assert Option\u003cT\u003e with #[serde(deserialize_with)] without explicit #[serde(default)] fails with missing field error on absent keys","assert Option\u003cT\u003e with #[serde(default, deserialize_with)] handles absent keys, explicit null, and formatted values"],"goal":"#[serde(default)] only applies when a field key is absent from the input mapping, failing with a type error on explicit null values, while adding deserialize_with to Option\u003cT\u003e suppresses implicit missing-key defaulting.","kind":"HOW","packages":["pkg:cargo/serde@1.0.229","pkg:cargo/serde_json@1.0.151"],"schemaVersion":1,"symbols":["serde::Deserialize","serde::de::Deserializer"]},"contractCommand":["cargo","test","--offline"],"environment":{"arch":"x64","ecosystem":"cargo","executionContext":"rust","language":"rust","os":"linux","packageManager":"cargo","runtime":"rust","schemaVersion":1},"license":"MIT-0","packages":["pkg:cargo/serde@1.0.229","pkg:cargo/serde_json@1.0.151"],"schemaVersion":1,"symbols":["serde::Deserialize","serde::de::Deserializer"],"verifierAdapter":"cargo@1"}
src/lib.rs
use serde::de::{self, Deserializer};
use serde::Deserialize;

fn parse_u32_from_str_or_num<'de, D>(deserializer: D) -> Result<Option<u32>, D::Error>
where
    D: Deserializer<'de>,
{
    #[derive(Deserialize)]
    #[serde(untagged)]
    enum StrOrNum {
        Num(u32),
        Str(String),
    }

    match Option::<StrOrNum>::deserialize(deserializer)? {
        Some(StrOrNum::Num(n)) => Ok(Some(n)),
        Some(StrOrNum::Str(s)) => s.parse::<u32>().map(Some).map_err(de::Error::custom),
        None => Ok(None),
    }
}

fn default_port() -> u16 {
    8080
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct ConfigWithDefaults {
    #[serde(default = "default_port")]
    pub port: u16,

    #[serde(default)]
    pub host: String,

    #[serde(default)]
    pub active: bool,

    #[serde(default)]
    pub tags: Vec<String>,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct ConfigWithDeserializeWithNoDefault {
    // Competent models write Option<u32> with deserialize_with, assuming Option is inherently optional.
    #[serde(deserialize_with = "parse_u32_from_str_or_num")]
    pub limit: Option<u32>,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct ConfigWithDeserializeWithAndDefault {
    // The correct way: must explicitly add #[serde(default)] when using deserialize_with on Option<T>.
    #[serde(default, deserialize_with = "parse_u32_from_str_or_num")]
    pub limit: Option<u32>,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_serde_default_works_when_key_is_absent() {
        let json = r#"{}"#;
        let cfg: ConfigWithDefaults = serde_json::from_str(json).unwrap();
        assert_eq!(cfg.port, 8080);
        assert_eq!(cfg.host, "");
        assert_eq!(cfg.active, false);
        assert_eq!(cfg.tags, Vec::<String>::new());
    }

    #[test]
    fn test_serde_default_fails_loudly_on_explicit_null() {
        // TRAP: Models confidently assume #[serde(default)] coerces JSON null into the default value.
        // ACTUAL: Serde only applies #[serde(default)] to absent keys.
        // When key is present with value `null`, serde invokes the type's deserializer which rejects null.
        
        let null_port = r#"{"port": null}"#;
        let err = serde_json::from_str::<ConfigWithDefaults>(null_port).unwrap_err();
        assert!(
            err.to_string().contains("invalid type: null, expected u16"),
            "Expected 'invalid type: null, expected u16', got: {}",
            err
        );

        let null_host = r#"{"host": null}"#;
        let err = serde_json::from_str::<ConfigWithDefaults>(null_host).unwrap_err();
        assert!(
            err.to_string().contains("invalid type: null, expected a string"),
            "Expected 'invalid type: null, expected a string', got: {}",
            err
        );

        let null_active = r#"{"active": null}"#;
        let err = serde_json::from_str::<ConfigWithDefaults>(null_active).unwrap_err();
        assert!(
            err.to_string().contains("invalid type: null, expected a boolean"),
            "Expected 'invalid type: null, expected a boolean', got: {}",
            err
        );

        let null_tags = r#"{"tags": null}"#;
        let err = serde_json::from_str::<ConfigWithDefaults>(null_tags).unwrap_err();
        assert!(
            err.to_string().contains("invalid type: null, expected a sequence"),
            "Expected 'invalid type: null, expected a sequence', got: {}",
            err
        );
    }

    #[test]
    fn test_deserialize_with_breaks_implicit_option_defaulting() {
        // TRAP: An unadorned `field: Option<T>` is implicitly optional when absent in JSON.
        // But adding `#[serde(deserialize_with = "...")]` suppresses serde derive's implicit
        // Option detection, causing missing fields to fail with "missing field" at runtime.

        let empty_json = r#"{}"#;
        let err = serde_json::from_str::<ConfigWithDeserializeWithNoDefault>(empty_json).unwrap_err();
        assert!(
            err.to_string().contains("missing field `limit`"),
            "Expected 'missing field `limit`', got: {}",
            err
        );

        // Explicit #[serde(default, deserialize_with = "...")] restores absent key handling
        let ok: ConfigWithDeserializeWithAndDefault = serde_json::from_str(empty_json).unwrap();
        assert_eq!(ok.limit, None);

        // When present with null, deserialize_with handles it
        let with_null = r#"{"limit": null}"#;
        let ok_null: ConfigWithDeserializeWithAndDefault = serde_json::from_str(with_null).unwrap();
        assert_eq!(ok_null.limit, None);

        // When present with value, deserialize_with parses it
        let with_val = r#"{"limit": "42"}"#;
        let ok_val: ConfigWithDeserializeWithAndDefault = serde_json::from_str(with_val).unwrap();
        assert_eq!(ok_val.limit, Some(42));
    }
}

Seeder d'origine

csx-seed