-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Poor error messages for untagged enums ("error occurred in:") #28
Comments
Ah, I had completely forgotten the last alternative here! Many of the various See https://docs.rs/toml/latest/toml/struct.Spanned.html, which looks fairly clean. And https://docs.rs/json-spanned-value/latest/json_spanned_value/, which appears to only work for spanned::Value(???), and which relies on a hacked We could implement something inspired by Note that to implement
So this is possible, but it's a huge project. |
Some other links from our original comments: |
OK, by inspecting the text of the error messages, and by adding two new custom ERROR: error parsing merged "Widget"
caused by: expected $ref, $interface or a schema with one of allOf, oneOf, or type: expected schema: data did not match any variant of untagged enum VecOrScalar
error occurred in:
---
type: foo
error occurred in:
---
type: foo ...into this: ERROR: error parsing merged "Widget"
caused by: unknown variant `foo`, expected one of `string`, `number`, `integer`, `object`, `array`, `boolean`, `null`
error occurred when expecting one of "string", "number", "integer", "object", "array", "boolean" or "null" in:
---
foo
---
...which appeared when expecting schema in:
---
type: foo
--- The most important part of this change is These errors may still be hard to find a in big source file, but at least they should be a lot clearer. Sadly, line numbers are not on the roadmap. |
openapi-interfaces
generates some particularly confusing error messages. These look something like:Sometimes, we may get several of these errors nested inside of each other, with multiple
error occurred in:
lines showing larger and smaller chunks of context. This is awful, but it's surprisingly hard to fix. I'm creating this bug to so I remember why, and don't need to work it out from first principles every couple of years.Untagged enums
An untagged enum uses
#[serde(untagged)]
to allow several different variants.On the wire, these interfaces look like:
We can tell them apart by checking for
$includes
andoneOf
.serde
parsing strategyTo parse
Interface
,serde
attempts to parse each of the three variants, and it takes the first one which matches. If we expand the#[derive(Deserializer)]
macro, we get:In pseudocode, this is:
The code first parses the object as a value of type
serde::__private::de::Content
(see below). This loses line & column number information, and it looks something like:There are a few unfortunate things going on in the generated deserializer:
"oneOf"
, and the actual error occurs many levels down inside, we still fail to matchOneOfInterface
, and we fall back to the unhelpful generic error.Things which don't work
serde::__private::de::Content
directly, because it's unstable and only allowed to be used in code generated byserde_derive
.Content
, it doesn't actually buy us anything, because it still loses line numbers.Content
withserde_yaml::Value
, which is basically the same thing. It also lacks line numbers.Content
type, and we'd still have trouble getting line numbers, becauseDeserialize
is normally implemented in a format-independent way, expecting an arbitrary implementation ofDeserializer
. And manyserde
formats don't have line numbers, soDeserializer
offers no generic way to get the current line number.Deserializer
to get line numbers,serde_yaml
doesn't provide them, anyways.yaml_rust
library used byserde_yaml
actually does have some line number support. SeeMarker
andmark
. But we'd have to patchserde_rust
to make this available.Also, if we use a tagged enum like:
...the generated code still goes through
Content
in some cases. Soserde
basically always follows the same strategy withenum
s in YAML-like formats that aren't "self-describing": Parse them toContent
, lose line numbers, then re-parseContent
.Our general approach
We use a custom
Deserialize
implementation that parses the input toserde_yaml:Mapping
, losing line number information. Then we usecontains_key
to manually check for each of our special keys. Once we figure out what kind of structure we're parsing, we parse it normally usingdeserialize_enum_helper
to consume ourserde_yaml:Mapping
.Drawbacks to this approach include:
serde
as raw strings, not structured errors. So it's hard to coordinate between multiple levels of tagged enums.Possible fixes
serde
fork might allow us to get rid of the customDeserialize
. But that would still leave the loss of line-number information, and the confusing errors from nested untagged enum types.The text was updated successfully, but these errors were encountered: