JSON Errors / Swift

Swift DecodingError: keyNotFound / typeMismatch / valueNotFound

How to Fix: Swift DecodingError: keyNotFound / typeMismatch / valueNotFound

JSONDecoder threw one of four DecodingError cases, and the case names the problem: keyNotFound (the JSON lacks a key your struct requires), valueNotFound (the value is null but the property is non-optional), typeMismatch (a string arrived where you declared Int), or dataCorrupted (the input is not valid JSON at all).

Each case carries a codingPath - the exact route to the failing field - and a debugDescription. Reading these two fields is the entire diagnosis; most frustration with Codable comes from not printing them.

{"find": "error"}paste your JSON below

Common causes

1. keyNotFound / valueNotFound - required vs actually-optional

The API omits or nulls a field your struct declares as non-optional.

Invalid
struct User: Codable { let nickname: String }
// {"name": "Ada"} -> keyNotFound(nickname)
Valid
struct User: Codable { let nickname: String? } // absent or null -> nil

2. typeMismatch - numbers sent as strings

APIs that serialize ids or amounts as "42" clash with Int/Double properties - common with PHP and older backends.

3. dataCorrupted - not JSON, or a date strategy mismatch

The body is HTML/empty, or a Date property is decoded without setting the matching dateDecodingStrategy.

How to fix it

Print the diagnosis, not just the error
do {
    let order = try JSONDecoder().decode(Root.self, from: data)
} catch let DecodingError.keyNotFound(key, context) {
    print("missing key '(key.stringValue)' at (context.codingPath.map(\.stringValue))")
} catch let DecodingError.typeMismatch(type, context) {
    print("expected (type) at (context.codingPath.map(\.stringValue)): (context.debugDescription)")
} catch {
    print("decode failed:", error)
}
Accept a string-or-number field
struct FlexibleInt: Codable {
    let value: Int
    init(from decoder: Decoder) throws {
        let c = try decoder.singleValueContainer()
        if let i = try? c.decode(Int.self) { value = i }
        else { value = Int(try c.decode(String.self)) ?? 0 }
    }
}

Frequently asked questions

The error says dataCorrupted but my JSON is valid. Why?

dataCorrupted is also thrown by value-level failures: a Date that does not match the dateDecodingStrategy, or a URL/Decimal that cannot be constructed from the string. Check context.codingPath - if it points at a date field, set decoder.dateDecodingStrategy to match the format.

How do I make decoding tolerant of a bad element in an array?

Decode elements as a lossy wrapper: try? container.decode(Element.self) inside a custom init, collecting successes and skipping failures (the "LossyCodableList" pattern). Default Codable is all-or-nothing per document - one bad element fails the whole array.

Why does everything work in the simulator but fail with real API data?

Fixtures drift from production: staging returns every field populated while production omits optionals or nulls them. Decode a captured production payload in a unit test - the codingPath in the failure tells you which struct property to relax.

Last updated:

Related JSON errors

You might also need

Free and in-browser, like everything on JSON Console. Browse all tools →