What the error means
serde's derived Deserialize treats every struct field as required unless told otherwise. When the JSON object has no key for a field, deserialization fails with missing field \email` at line 1 column 9` — the position is where the object ended, because that is when serde knew the field was never coming. There is no partial struct; the whole value is rejected.
In the example, the first record contains email and the second does not. A struct generated from the first record declares email: String, which makes the key mandatory, so the second record fails.
Why it happens
- The generation sample always contained the key.
- The key is optional in the producer's contract, present for some records and absent for others.
- A field that is nullable but not optional.
email: Option<String>accepts"email": nulland an absent key — serde treats a missingOptionfield asNoneby default — but a field of typeStringdoes not, and neither does a custom type without#[serde(default)]. - A rename mismatch: the JSON key is
user_emailand the field isemailwithout#[serde(rename = "user_email")], so the key is present but unmatched.
How to fix it
- Paste a sample that includes a record without the key into the generator above. It merges the records and emits
Option<String>for any field absent from at least one; serde then decodes an absent key asNonewith no further annotation. - In an existing struct, change the type to
Option<String>, or keep the type and add#[serde(default)]to fall back toDefault::default()— an empty string, zero, an empty vector — when the key is missing. - For a specific fallback, use
#[serde(default = "path::to::fn")]. - If the JSON key has a different name, add
#[serde(rename = "...")]or a struct-level#[serde(rename_all = "camelCase")]rather than renaming the field.
The struct that accepts both records:
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
pub id: i64,
pub email: Option<String>,
}
If it still fails
#[serde(deny_unknown_fields)]is the opposite concern — it rejects extra keys — and does not interact with this error.- If the message names a field inside a nested struct, the
Optionordefaultbelongs on the inner struct's field. - Go and Kotlin apply the same required-by-default rule; JSON to Go uses pointers with
omitemptyand JSON to Kotlin usesT? = nullfor the same optional key.
Related errors
invalid type: string "42", expected i64
Change the field to String if the value is an identifier, or deserialize with serde_with's DisplayFromStr when it is a number that arrives quoted.
MissingFieldException: Field 'email' is required for type with serial name 'Root', but it was missing
Give the property a default (val email: String? = null), which the generator emits when any sample omits the key; or make the producer always send it.