What the error means
kotlinx.serialization treats a data class as a contract. Every property that has no default value is required, and if the JSON does not contain a key for it, decoding fails with MissingFieldException: Field 'email' is required for type with serial name 'Root', but it was missing. The message names the property and the class, and — since Kotlin 1.7 — the full path when the class is nested.
In the example, the first record has email and the second does not. A class generated from the first record alone declares val email: String, which makes email mandatory, so the second record throws.
Why it happens
- The generation sample always contained the key, so the property was emitted as non-nullable with no default.
- The key is genuinely optional in the producer's contract — present for some users, absent for others.
- A nullable type without a default.
val email: String?still throws when the key is absent; nullable means the value may benull, not that the key may be missing. Only a default makes the key optional. explicitNullsconfusion: withexplicitNulls = falseon theJsoninstance, absent keys are treated as null for nullable properties, which changes the behaviour without changing the class.
How to fix it
- Paste a sample that includes a record without the key into the generator above. It merges the records and emits
val email: String? = nullfor any property absent from at least one — nullable and defaulted, which is what makes the key optional. - In an existing class, add the default:
val email: String? = null. Keep the type nullable unless a non-null default (= "") is genuinely correct for your domain. - If the key must always be present, fix the producer instead; a required field that is sometimes missing is a data bug the exception is correctly reporting.
- If many properties are optional, consider
Json { explicitNulls = false }so that absent keys map to null without a default on each property — but read the documentation; it also changes encoding (nulls are omitted).
The class that accepts both records:
@Serializable
data class Root(
val id: Long,
val email: String? = null
)
If it still fails
- Jackson, serde, and Pydantic each have their own version of this rule; JSON to Java and JSON to Rust show how the same optional key is declared there.
ignoreUnknownKeysis the mirror setting — it governs extra keys, not missing ones — and does not affect this error.- If the exception names a nested type, the optional property is on the inner class; the fix is the same there.
Related errors
Field required
Declare the field with a default (nickname: Optional[str] = None); the generator does this for any key absent from at least one sample.
missing field `email`
Make the field Option<String> (the generator does this when any sample omits the key) or add #[serde(default)] to fall back to a default value.