Swift
JSONDecode
ErrorHandling
Arrays
Coding

Swift JSONDecode decoding arrays fails if single element decoding fails

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

This behavior is the default design of Swift decoding, not a bug in JSONDecoder. When you decode an array of Decodable values, one invalid element causes the entire array decode to fail because the decoder treats the array as one atomic value.

Why the whole array fails

JSONDecoder does not silently skip bad elements for you. If you ask it to decode [User], it attempts to decode every entry as a User. The first mismatch throws an error, and the whole array decode stops.

That is consistent with Swift's emphasis on type safety. The decoder assumes that if you requested [User], every array element should be valid under that contract.

Example of the default failure

swift
1import Foundation
2
3struct User: Decodable {
4    let id: Int
5    let name: String
6}
7
8let json = """
9[
10  {"id": 1, "name": "Ava"},
11  {"id": "bad", "name": "Liam"},
12  {"id": 3, "name": "Mia"}
13]
14""".data(using: .utf8)!
15
16do {
17    let users = try JSONDecoder().decode([User].self, from: json)
18    print(users)
19} catch {
20    print(error)
21}

The invalid second element stops the entire array decode. You do not get elements one and three automatically.

Build a lossy wrapper when skipping bad items is acceptable

If your application wants "decode what you can and skip broken elements," you need a custom strategy. A common pattern is to decode each element into a wrapper that can absorb failure.

swift
1import Foundation
2
3struct User: Decodable {
4    let id: Int
5    let name: String
6}
7
8struct FailableDecodable<Base: Decodable>: Decodable {
9    let value: Base?
10
11    init(from decoder: Decoder) throws {
12        let container = try decoder.singleValueContainer()
13        value = try? container.decode(Base.self)
14    }
15}
16
17let json = """
18[
19  {"id": 1, "name": "Ava"},
20  {"id": "bad", "name": "Liam"},
21  {"id": 3, "name": "Mia"}
22]
23""".data(using: .utf8)!
24
25let wrapped = try JSONDecoder().decode([FailableDecodable<User>].self, from: json)
26let users = wrapped.compactMap(\.value)
27print(users.count)

This is a lossy decode. That is the right name for it because the output intentionally discards malformed elements.

Decide whether lossy decoding is correct

Skipping invalid elements is not always the right behavior. For some APIs, one bad item means the server response is corrupted and the safest answer is to fail the whole decode. For telemetry, logs, or partially trusted feeds, lossy decoding may be perfectly reasonable.

The design question is not only technical. It is about data integrity. Do you want strict failure or best-effort recovery?

Manual array decoding for better diagnostics

If you need to know which element failed and why, you can decode with a custom initializer and iterate through an unkeyed container manually. That gives you more control over error handling, logging, and partial recovery than the plain array decode API.

Model the tolerance explicitly

The key design point is that tolerant decoding is a different contract from normal decoding. Once you choose to skip invalid elements, document that behavior clearly so callers do not assume the output array is a strict representation of the original payload.

Common Pitfalls

  • Expecting JSONDecoder to skip one invalid array element automatically.
  • Adding lossy decoding without deciding whether silent recovery is appropriate for the data source.
  • Using try? everywhere and losing useful diagnostics about what failed.
  • Forgetting that a wrapper-based solution changes the semantics from strict decoding to best-effort decoding.
  • Treating bad server payloads as harmless when the application actually needs strict correctness.

Summary

  • Default array decoding in Swift is all-or-nothing.
  • One invalid element causes [T] decoding to fail.
  • If you want to skip bad elements, build an explicit lossy decoding strategy.
  • Use strict decoding when data integrity matters more than partial recovery.
  • Choose the behavior deliberately instead of assuming JSONDecoder will skip failures for you.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.