# SE-0396: Conform Never to Codable

**URL:** <https://forums.swift.org/t/se-0396-conform-never-to-codable/64469>\
**Category:** Proposal Reviews\
**Created:** [April 18, 2023, 10:19pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469 "2023-04-18T22:19:37Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![taylorswift](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/taylorswift/32/43413_2.png) [@taylorswift](https://forums.swift.org/u/taylorswift)\
**Post date:** [April 20, 2023, 2:18am UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/21 "2023-04-20T02:18:05Z")

</div>

> [@ExFalsoQuodlibet](#):
>
> in other words, if you absolutely cannot avoid crashing, you should crash as early as possible, but you should still avoid crashing in general.

this is also true in algorithmic trading. if you crash in the middle of a trade (i.e. before you have hedged) recovery can be very painful. i once got into an argument with a friend who is a C++ algotrader, over whether crash on precondition failure is a good idea. (he won.)

---

<div class="post-metadata">

**Author:** ![taylorswift](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/taylorswift/32/43413_2.png) [@taylorswift](https://forums.swift.org/u/taylorswift)\
**Post date:** [April 20, 2023, 2:22am UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/22 "2023-04-20T02:22:48Z")

</div>

> [@Jumhyn](#):
>
> I don’t know, IMO `dataCorrupted` does a better job communicating that something must have gone seriously wrong for you to decode a `Never`

not always seriously wrong, you might just be doing schema validation. if you decode `Never`, that means you are decoding a newer/unsupported version of the schema, and you need to update the client to decode it.

> [@ktoso](#):
>
> Trying to decode a Never throwing `dataCorrupted` seems backwards to me. It is not the data that may be corrupted but the logic attempting to do such decoding. The data may be totally fine `{"hi": 1}` but code may be doing something weird and wrongly attempt to decode it as `Never` -- it is a typeMismatch to me is a more logical error to throw, or something like "cannot decode Never" that is very specific about what is happening.

exactly

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [April 20, 2023, 3:32pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/23 "2023-04-20T15:32:31Z")

</div>

> [@taylorswift](#):
>
> if you decode `Never`, that means you are decoding a newer/unsupported version of the schema, and you need to update the client to decode it.

From the perspective of such a client, what's the difference between "data encoded by a newer client with a different schema" and "data that is corrupt with respect to the current schema"? Communicating that via "I decoded a `Never`" seems kinda dubious anyway, and I'm not sure `typeMismatch` would accurately describe this situation either.

> [@ktoso](#):
>
> The data may be totally fine `{"hi": 1}` but code may be doing something weird and wrongly attempt to decode it as `Never` -- it is a typeMismatch to me is a more logical error to throw, or something like "cannot decode Never" that is very specific about what is happening.

Invalid JSON is certainly one way that data can be corrupt, but it's not the only way. I don't think its possible to say that `{"hi": 1}` is 'totally fine' in a vacuum, but if its being used to decode a type which will attempt to decode `Never` for that data due to some broken invariant, it doesn't seem reasonable to say that the _data_ is fine.

---

<div class="post-metadata">

**Author:** ![taylorswift](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/taylorswift/32/43413_2.png) [@taylorswift](https://forums.swift.org/u/taylorswift)\
**Post date:** [April 20, 2023, 9:12pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/24 "2023-04-20T21:12:47Z")

</div>

> [@Jumhyn](#):
>
> From the perspective of such a client, what's the difference between "data encoded by a newer client with a different schema" and "data that is corrupt with respect to the current schema"? Communicating that via "I decoded a `Never`" seems kinda dubious anyway, and I'm not sure `typeMismatch` would accurately describe this situation either.

one of them can be an expected failure when clients are gradually being migrated to a newer version. but there are many kinds of data corruption that should never be expected, they indicate that something is wrong with the server/cluster or something malicious/malformed made it past server-side schema validation.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [April 20, 2023, 9:38pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/25 "2023-04-20T21:38:17Z")

</div>

What I'm getting at is that to the outdated client, it all looks the same. It's all data which doesn't conform to the expected schema unless you build specific logic to catch the "encoded by a newer client" situation, in which case it seems to me that `typeMismatch` and `dataCorrupted` are both equally inappropriate errors—you probably want some bespoke `wrongVersion` error that you've designed for the specific purpose rather than just having some general error fall out of the decoding process.

---

<div class="post-metadata">

**Author:** ![1-877-547-7272](https://avatars.discourse-cdn.com/v4/letter/1/278dde/32.png) [@1-877-547-7272](https://forums.swift.org/u/1-877-547-7272)\
**Post date:** [April 21, 2023, 3:41am UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/26 "2023-04-21T03:41:50Z")

</div>

+1 on the general concept, but I agree with other commenters here that attempting to decode a `Never` should throw a `typeMismatch` instead of `dataCorrupted`.

`typeMismatch` is a more accurate error than `dataCorrupted` — it's [described as](https://developer.apple.com/documentation/swift/decodingerror/typemismatch(_:_:)) "an indication that a value of the given type could not be decoded because it did not match the type of what was found in the encoded payload", which is exactly the error that occurred in the situation. Trying to decode a `Never` value could indicate that the data is corrupt in some contexts, but interpreting that should be left to the caller. Additionally, in a JSON decoding context, `dataCorrupted` specifically means that the data is not valid JSON, not just that the data is considered "invalid" (see my response to Jumhyn below).

`typeMismatch` is also a more precise error than `dataCorrupted` — If you see a `typeMismatch(Never.self, ...)`, you can be pretty sure it came from trying to decode a `Never` value. If you see a `dataCorrupted` error, then there's no hint that it came from trying to decode a `Never`.

* * *

> [@Jumhyn](#):
>
> Invalid JSON is certainly one way that data can be corrupt, but it's not the only way.

The [documentation for `JSONDecoder.decode`](https://developer.apple.com/documentation/foundation/jsondecoder/2895189-decode) states:

> If the data isn’t valid JSON, this method throws the [`DecodingError.dataCorrupted(_:)`](https://developer.apple.com/documentation/swift/decodingerror/datacorrupted(_:)) error. If a value within the JSON fails to decode, this method throws the corresponding error.

Decoding a `Never` doesn't mean the data isn't valid JSON, so `dataCorrupted` wouldn't be an appropriate error to throw in that context.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [April 21, 2023, 4:06am UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/27 "2023-04-21T04:06:52Z")

</div>

> [@1-877-547-7272](#):
>
> The [documentation for `JSONDecoder.decode`](https://developer.apple.com/documentation/foundation/jsondecoder/2895189-decode) states:
> 
> > If the data isn’t valid JSON, this method throws the [`DecodingError.dataCorrupted(_:)`](https://developer.apple.com/documentation/swift/decodingerror/datacorrupted(_:)) error. If a value within the JSON fails to decode, this method throws the corresponding error.
> 
> Decoding a `Never` doesn't mean the data isn't valid JSON, so `dataCorrupted` wouldn't be an appropriate error to throw in that context.

`JSONDecoder`, defined in Foundation, _uses_ `DecodingError.dataCorrupted`, defined in the standard library, to communicate that the decoder encountered invalid JSON, but this doesn’t mean that the only way for data to be corrupted is for it to be invalid JSON.

Anyway, at this point I’m probably arguing beyond how strongly I feel about the choice of specific error here. 🙂

With a decent debug description I think both options are acceptably expressive.

---

<div class="post-metadata">

**Author:** ![ExFalsoQuodlibet](https://avatars.discourse-cdn.com/v4/letter/e/bbce88/32.png) [@ExFalsoQuodlibet](https://forums.swift.org/u/ExFalsoQuodlibet)\
**Post date:** [April 21, 2023, 6:54am UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/28 "2023-04-21T06:54:54Z")

</div>

The way I interpret `DecodingError.typeMismatch` is "in the data, I expected to find the type I declared in my model, and instead I found \_\_\_", so **the point of reference is the model** , not the data.

For example, with this model

```swift
struct Foo<Bar>: Decodable where Bar: Decodable {
  var bar: Bar?
  var baz: String
}

struct PossibleBar: Decodable {
  var value: Int
}

```

if I try to decode `Foo<PossibleBar>` from the JSON data

```json
{
  "bar": {
    "value": 42
  },
  "baz": { "ok": 1 }
}

```

I get `DecodingError.typeMismatch` with description `Expected to decode String but found a dictionary instead.`, so it's clear that what I "expect" is what I declared in the model.

But if my model is `Foo<Never>`, I don't "expect" to decode a `Never` at the `bar` key... the point of `Never` is exactly that it cannot be instantiated. So, if I try to decode this JSON data

```json
{
  "bar": true,
  "baz": "yello"
}

```

Getting a `DecodingError.typeMismatch` with description `Expected to decode Never but found a Bool instead.` makes no sense, I cannot expect to decode `Never`, and I use `Never` precisely to express the fact that I don't expect to decode something at that key.

The only valid JSON data would be

```json
{
  "bar": null,
  "baz": "yello"
}

```

or

```json
{
  "baz": "yello"
}

```

so I feel that "data corrupted" better represents the underlying issue (if we don't add a completely new error case).

---

<div class="post-metadata">

**Author:** ![sveinhal](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/sveinhal/32/3992_2.png) [@sveinhal](https://forums.swift.org/u/sveinhal)\
**Post date:** [April 21, 2023, 7:29am UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/29 "2023-04-21T07:29:28Z")

</div>

Solution: Add a new error type:

```swift
extension Never {
    enum DecodingError: Error { ... }
}

```

---

<div class="post-metadata">

**Author:** ![ExFalsoQuodlibet](https://avatars.discourse-cdn.com/v4/letter/e/bbce88/32.png) [@ExFalsoQuodlibet](https://forums.swift.org/u/ExFalsoQuodlibet)\
**Post date:** [April 21, 2023, 7:43am UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/30 "2023-04-21T07:43:10Z")

</div>

I don't think that's good idea: it's simpler to always expect a `DecodingError` from `JSONDecoder`, in case we do some extra logic based on the error type (in the case of my team, we do). I'd prefer a new `case` on `DecodingError`, but overall I think thet simply using `dataCorrupted` is the best solution.

---

<div class="post-metadata">

**Author:** ![bbrk24](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/bbrk24/32/27370_2.png) [@bbrk24](https://forums.swift.org/u/bbrk24)\
**Post date:** [April 21, 2023, 1:49pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/31 "2023-04-21T13:49:59Z")

</div>

> [@ExFalsoQuodlibet](#):
>
> I'd prefer a new `case` on `DecodingError`

Is this even possible? In general, adding a new case to an existing enum is source-breaking.

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [April 21, 2023, 2:19pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/32 "2023-04-21T14:19:25Z")

</div>

> [@ExFalsoQuodlibet](#):
>
> Getting a `DecodingError.typeMismatch` with description `Expected to decode Never but found a Bool instead.` makes no sense, I cannot expect to decode `Never`, and I use `Never` precisely to express the fact that I don't expect to decode something at that key.

This is muddling the agent here: the _"I"_ who is doing the decoding isn't the _"I"_ who is choosing `Never` for the generic parameter. If we reject the argument that it isn't definitely a logic error to try to decode `Never` (e.g., in the generic context; see @Joe_Groff's post), then attempting to decode would be a fatal error. However, if we accept that argument (and thus attempting to decode should throw), then we are saying it _does_ make sense that _"I"_ (the decoder) expects to try to decode `Never`, and the most specific description of the problem is that the data encountered is an instance of a different type.

---

<div class="post-metadata">

**Author:** ![ExFalsoQuodlibet](https://avatars.discourse-cdn.com/v4/letter/e/bbce88/32.png) [@ExFalsoQuodlibet](https://forums.swift.org/u/ExFalsoQuodlibet)\
**Post date:** [April 21, 2023, 2:49pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/33 "2023-04-21T14:49:31Z")

</div>

> [@xwu](#):
>
> if we accept that argument (and thus attempting to decode should throw), then we are saying it _does_ make sense that _"I"_ (the decoder) expects to try to decode `Never`, and the most specific description of the problem is that the data encountered is an instance of a different type.

I don't think I agree (or maybe I don't understand your point). I definitely think that attempting to decode `Never` should `throw` an error, but the error to me is caused by the fact that, with `Never`, I (the programmer) am saying "I don't expect to decode this at all", not "I do expect to decode this specific type, and instead I'm getting a different type": the fact that the data that I received will make the decoder try to decode it seems to me bad data, rather than data that makes sense but I'm not modeling it correctly, because of the semantics that I want to express with `Never`. In other words, if I write `Never` I'm not saying "I expect to decode `Never`": I'm instead effectively saying "no type is fine here".

The error produced when "no type is fine here" might as well be `typeMismatch`, but the latter, at least to me, seems a little more "recoverable", like "you wanted type X and instead got type Y", which is not what I would express with `Never`.

---

<div class="post-metadata">

**Author:** ![jeremyabannister](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jeremyabannister/32/10143_2.png) [@jeremyabannister](https://forums.swift.org/u/jeremyabannister)\
**Post date:** [April 21, 2023, 3:18pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/34 "2023-04-21T15:18:41Z")

</div>

IIUC, the current debate is basically:

"If we take a chunk of `Data` and hand it to the `Never` type so that it can make an instance of itself, what error should we throw?"

I know that making `Never` conform to `Codable` requires us to answer this question.

(_For the record I think I'm convinced by Xiaodi's arguments for `typeMismatch`_)

Does anyone else agree with me that it may prove relevant to that debate to simultaneously discuss ways in which we can avoid calling `Never.init(from:)` in the first place?

Specifically, again, I'm proposing that it really should be the responsibility of `Result<Int, Never>` to handle throwing a truly correct error when decoding the data: `{"failure":{"errorCode":1}}`

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [April 21, 2023, 3:20pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/35 "2023-04-21T15:20:03Z")

</div>

> [@ExFalsoQuodlibet](#):
>
> I definitely think that attempting to decode `Never` should `throw` an error, but the error to me is caused by the fact that, with `Never`, I (the programmer) am saying "I don't expect to decode this at all"

If you, the writer of code that’s doing the decoding, expect never to attempt decoding `Never`, then it’s a logic error if your code ends up attempting to do so. If you, the writer of the post, think that’s _necessarily_ what goes on every time an attempt to decode `Never` takes place, then it’s not a recoverable error and should not throw but fatal error.

Put another way, if you believe in the second half of your statement above, then Swift’s error handling philosophy would disagree with the first half of your statement, and vice versa.

To be clear, I am convinced by Joe’s argument that it’s _not_ necessarily a logic error to attempt to decode `Never`, for which reason I agree with throwing an error. But it it’s not a logic error, then the reason that best describes the recoverable problem in my view is that the data being decoded has a value there, which is necessarily of some type other than `Never`, where no value can be instantiated.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [April 21, 2023, 3:32pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/36 "2023-04-21T15:32:30Z")

</div>

I think implicit in "I don't expect to decode this at all" is "_from valid data_," and the nature of `Codable` is that it is deliberately robust against potentially invalid data. I understand the view that decoding `Never` is in some sense a type error since `Never` is the canonical type which admits no values, but it still strikes me as somewhat different in kind than other sorts of type errors.

I think the idea of recoverability that @ExFalsoQuodlibet brings up gets at the mental disconnect I'm feeling. With a `typeMismatch` error decoding the key `"foo"` from some piece of data `{ "foo": ... }` it feels like there's an implicit expectation that you could resolve the error by adjusting the type of the data in `...`, but when it comes to `Never` the error occurs before you even get to inspecting `...`—the data was invalid as soon as you found the key at all.

---

<div class="post-metadata">

**Author:** ![nnnnnnnn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nnnnnnnn/32/264_2.png) [@nnnnnnnn](https://forums.swift.org/u/nnnnnnnn)\
**Post date:** [April 21, 2023, 3:34pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/37 "2023-04-21T15:34:08Z")

</div>

Thanks for this discussion so far!

I've taken a look at the ways that errors are used in `JSONDecoder`, and the `dataCorrupted` error seems to be used both in cases of invalid syntax (e.g. malformed JSON) or invalid data (e.g. an invalid date or URL string). Given that, I agree with those arguing that the `typeMismatch` error is a better fit. In addition, given the existing documented errors, `typeMismatch` is a more useful error for a developer who encounters this kind of error than the alternatives (either `dataCorrupted` or a new error created for this purpose).

I've updated [the implementation](https://github.com/apple/swift/pull/64899) and [the proposal](https://github.com/apple/swift-evolution/pull/2020) with this change.

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [April 21, 2023, 3:35pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/38 "2023-04-21T15:35:15Z")

</div>

> [@jeremyabannister](#):
>
> Does anyone else agree with me that it may prove relevant to that debate to simultaneously discuss ways in which we can avoid calling `Never.init(from:)` in the first place?
> 
> Specifically, again, I'm proposing that it really should be the responsibility of `Result<Int, Never>` to handle throwing a truly correct error when decoding the data: `{"failure":{"errorCode":1}}`

Can you clarify why you think it “should” be that way? Why would it be insufficient to delegate to `Never.init(from:)`? If there isn’t a single correct way to implement an initializer attempting to decode `Never`, then isn’t that an argument that `Never` doesn’t truly meet the semantic requirements of conformance and we ought to reject this altogether?

---

<div class="post-metadata">

**Author:** ![jeremyabannister](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jeremyabannister/32/10143_2.png) [@jeremyabannister](https://forums.swift.org/u/jeremyabannister)\
**Post date:** [April 21, 2023, 3:47pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/39 "2023-04-21T15:47:01Z")

</div>

> [@xwu](#):
>
> isn’t that an argument that `Never` doesn’t truly meet the semantic requirements of conformance and we ought to reject this altogether?

Well yes, immediately after my last post I started writing a new post suggesting that we reject this pitch (on the grounds that it is philosophically unsound to conform `Never` to a protocol with initializer requirements) and approach enabling the desired use case (e.g. `Result<Int, Never>` being codable) in a different way, but then I realized some conceptual complications so I deleted it to keep thinking about it.

> [@xwu](#):
>
> If there isn’t a single correct way to implement an initializer attempting to decode `Never`,

This is exactly why I'm saying that we "should" consider thinking one level up from the data that we're attempting to decode as `Never`, because up there (e.g. at the level of `Result<Int, Never>` instead of at the level of `Never`) there is a more objectively correct error to throw (namely, whatever error a normal enum throws when trying to decode itself from: `{"notOneOfItsCaseNames":{"someData":7}}`).

The alternative that I was going to propose can be hand-wavily described like this:

"Rather than `Never` conforming to `Codable` such that all of the cases of `Result<Int, Never>` are `Codable` such that `Result<Int, Never>` is `Codable`, we instead give `Never` the special power to "stamp out" individual cases from enums, allowing whatever's left to conform to `Codable` if it is able, thereby avoiding this impossible question of which error to throw when decoding `Never` directly."

However, as I began to think about the completely concrete proposition I was making I began to have doubts about its coherence. Since you asked though, I've written here what I have in mind so far so that anyone who wants to can run with it.

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [April 21, 2023, 3:53pm UTC](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469/40 "2023-04-21T15:53:21Z")

</div>

> [@Jumhyn](#):
>
> I think the idea of recoverability that @ExFalsoQuodlibet brings up gets at the mental disconnect I'm feeling. With a `typeMismatch` error decoding the key `"foo"` from some piece of data `{ "foo": ... }` it feels like there's an implicit expectation that you could resolve the error by adjusting the type of the data in `...`, but when it comes to `Never` the error occurs before you even get to inspecting `...`—the data was invalid as soon as you found the key at all.

That's a great point. Conceptually, with one expects data of type `A` but finds data of type `B`, one can reconcile the problem either way, and it's certainly true that going in one of those directions is foreclosed in the case of `Never`.

Notionally, though, that represents a degenerate case rather than a difference in kind. Pragmatic considerations may override, but I find it hard to imagine, in the generic context where attempting to decode `T` isn't necessarily a logic error where `T == Never`, how such code could "adjust the data" to be valid for any type `T` upon encountering `DecodingError.typeMismatch` _but for_ the `Never` case.

[Previous page](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469.md?page=1)

[Next page](https://forums.swift.org/t/se-0396-conform-never-to-codable/64469.md?page=3)
