I was surprised to see that the codingPath
contained inside of DecodingError
is not populated with the full chain of coding keys when the error is thrown manually.
For example, the following code:
func test_nestedDecodingError() {
try! JSONDecoder()
.decode(
Foo.self,
from: "{\"bar\": {\"bool\": true}}".utf8Data
)
}
struct Foo: Decodable {
var bar: Bar
}
struct Bar: Decodable {
var bool: Bool
init(from decoder: any Decoder) throws {
throw
DecodingError.keyNotFound(
CodingKeys.someKey,
DecodingError.Context(
codingPath: [CodingKeys.someKey],
debugDescription: "abc"
)
)
}
enum CodingKeys: CodingKey {
case someKey
}
}
yields the following error:
Swift.DecodingError.keyNotFound(
CodingKeys(stringValue: "someKey", intValue: nil),
Swift.DecodingError.Context(
codingPath: [CodingKeys(stringValue: "someKey", intValue: nil)],
debugDescription: "abc",
underlyingError: nil
)
)
Why is the codingPath
not the following?
[
CodingKeys(stringValue: "bar", intValue: nil),
CodingKeys(stringValue: "someKey", intValue: nil)
]
1 Like
JSONEncoder
/JSONDecoder
(and other encoders and decoders) don't intercept-and-rethrow errors you throw, at least partially for performance, and partially because you could want to construct a custom codingPath
to report that doesn't directly match the stack, for a variety of reasons; so, what you throw is what you get.
DecodingError
does offer
as conveniences, which automatically construct the appropriate codingPath
for you using the container's codingPath
, though unfortunately not for keyNotFound
or the other error variants (since those are usually just thrown automatically when you attempt to access a non-existent key).
Theoretically, DecodingError
could offer similar methods for the other error types to do the same thing.
2 Likes
Are there any internal plans for doing that or we should better write a pitch?
I fall into the same issue sometimes. Appropriate errors are substantial for logging of nonfatal errors and network requests tracing.
I'm not aware of any plans to add new conveniences (not that I would have internal knowledge), but it seems like a straightforward pitch to me 
@jeremyabannister do you have time and motivation to collaborate for making a detailed pitch?
I do have general interest in collaborating on a pitch to improve Swift in some way, but my motivation is not very strong on this particular one at the moment, since so far it doesn't look like it will help me with what I'm working on right now, and I haven't tried to imagine other situations where I would need it.
Like I said though, I may be interested in collaborating on other pitches in the future though, so feel free to reach out.
1 Like
I now realize that Decoder
provides a codingPath
property which solves my needs, and I don't think the convenience methods you mentioned fit my use case. Thanks though for indirectly leading me to what I needed!