fix: an unknown discriminator value no longer fails the whole decode - #41
Merged
Merged
Conversation
A generated discriminated union returned an error for any variant it did not know, so adding a member to a oneOf broke every client build that predated it. Because unions are commonly list elements, a single unrecognized entry failed the entire response and the recognized entries went with it. The unknown variant is now preserved instead: Value stays nil, the original JSON is kept on the wrapper, and MarshalJSON returns those bytes unchanged so a re-marshal is lossless. IsUnknownVariant, UnknownDiscriminator, and Raw let callers handle the case explicitly. Unions without a discriminator still error when no variant matches. Fixes #39
This was referenced Aug 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #39
The bug
A generated discriminated union's
UnmarshalJSONended in:Adding a member to a
oneOfis normally an additive, backward-compatible change — under an untyped decode a new variant is simply inert until the client is rebuilt. Here it broke every deployed client at decode time, with no server-side signal. And since unions are usually list elements, one unrecognized entry in a hundred failed the entire response, so the client couldn't process the variants it did understand.The fix
An unrecognized discriminator value is preserved rather than rejected. The wrapper gains two unexported fields and three accessors:
UnmarshalJSON'sdefaultbranch stores the discriminator value and a copy of the payload, and returns nil.MarshalJSONreturns those bytes verbatim for an unknown variant, so a decode/encode round trip is lossless.*u = Shape{Value: v}, so a reused variable can't keep stalerawfrom a prior decode.Unions without a discriminator are unchanged — they still error when no variant matches, since there's nothing to identify the payload by. Output for those types is byte-identical to before.
Caller-side shape
A caller that wants the old strictness can check
IsUnknownVariant()and fail; a caller that doesn't gets the additive behavior spec authors assume.Trade-off worth naming
A payload missing the discriminator property entirely now decodes as an unknown variant (empty discriminator) instead of erroring. That's the same code path as an unrecognized value, and
IsUnknownVariant()lets a strict caller reject it.Tests
TestE2E_InlineUnionRuntimeDispatch— which compiles and runs the generated client — is extended: an unmappedshapeTypenow decodes, reportsIsUnknownVariant()/UnknownDiscriminator() == "hexagon", and re-marshals with its"sides":6payload intact. Its previous assertion that this errored is replaced.New
TestUnknownVariantDoesNotFailSiblingscovers the issue's central complaint directly: a collection holding onecircleand one unknowntriangledecodes successfully, with the circle typed and the triangle flagged.README documents the behavior. Full suite and
go vetpass.