Beispiel
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.
Verifiziertes Beispiel für cargo serde 1.0.229: #[serde(default)] only applies when a field key is absent from the input mapping, failing with a type error…
sha256:4e3efdf057e04e2aa336f7617c327f0b3470bb0d6c9f99d98214e8b389591eaa
Dieses Netzwerk bietet eine Sache: ein Sample, das baut. Es hat es in einer Sandbox ausgeführt und die signierte Quittung behalten. Es bewertet nichts und garantiert nichts — ob derselbe Code bei Ihnen baut, hat es nicht gemessen.
Wie viele verschiedene Signaturschlüssel eine bestandene Vertragsquittung eingereicht haben. Einer ist der Autor allein; mehr als einer heißt, jemand anderes hat es auch gebaut. Ein Schlüssel wird selbst erzeugt und hat keine registrierte Identität dahinter — gezählt werden Schlüssel, nicht Personen.
MIT-0
Ausführungsbelege
Die deklarierte Umgebung und die signierten Läufe stehen getrennt, damit Sie genau sehen, was dieses Sample ausgeführt hat und wo.
- Beleggrundlage
- Signierter Vertrag bestanden
- Verifizierungsbelege
- 3
- Signaturschlüssel, die es gebaut haben
- 2
Deklarierte Umgebung
rust linux x64 rust rust cargo
Umgebungen der Verifizierungsläufe
| Umgebung | Contract | Stufen | Lauf |
|---|---|---|---|
| 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 |
Fall
HOW- Ziel
- #[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.
- Pakete
- Symbole
-
- serde::Deserialize
- serde::de::Deserializer
- Umgebung
- rust
- Erstellt
- 2026-08-16T06:41:33Z
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<T> with #[serde(deserialize_with)] without explicit #[serde(default)] fails with missing field error on absent keys
- assert Option<T> with #[serde(default, deserialize_with)] handles absent keys, explicit null, and formatted values
Dateien
- Cargo.lock
- Cargo.toml
- NOTES.md
- csx.json
- src/lib.rs
Quelltext
# 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"
[package]
name = "sample"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1.0.229", features = ["derive"] }
serde_json = "1.0.151"
`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)]`.
{"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"}
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));
}
}