Skip to content

fix: disambiguate struct unions when multiple variants share a discriminator value#692

Open
rsd-darshan wants to merge 1 commit into
openai:mainfrom
rsd-darshan:fix/union-discriminator-tiebreak
Open

fix: disambiguate struct unions when multiple variants share a discriminator value#692
rsd-darshan wants to merge 1 commit into
openai:mainfrom
rsd-darshan:fix/union-discriminator-tiebreak

Conversation

@rsd-darshan

Copy link
Copy Markdown

Summary

When a struct union registers more than one variant under the same discriminator value (for example, several "message" shaped variants distinguished only by other fields like role or the presence of an id), newStructUnionDecoder always picked whichever matching variant was registered first, regardless of which one the data actually matched.

For ResponseInputItemUnionParam, three variants (EasyInputMessageParam, ResponseInputItemMessageParam, ResponseOutputMessageParam) are all registered under "type":"message". As a result, decoding an output message echoed back into the input (e.g. {"id":"msg_1","type":"message","role":"assistant","status":"completed","content":[...]}) always landed on EasyInputMessageParam, dropping the id/status fields.

Fix

When more than one registered variant matches the discriminator value, compare each candidate's own recognized JSON field names against the object's top-level keys and decode whichever one accounts for the most of them, instead of decoding the first match unconditionally. The existing single-match fast path is unchanged.

Test plan

  • Added a test in internal/apijson/decodeparam_test.go that registers two variants under the same discriminator value and asserts both directions resolve to the correct variant.
  • Verified the new test fails against the pre-fix code and passes with the fix.
  • go test ./... passes with no regressions.

…minator value

newStructUnionDecoder picked the first registered variant whose
discriminator matched, even when several variants share the same value
(for example, several "message" shaped variants distinguished only by
other fields like role or the presence of an id). When more than one
variant matches, now pick whichever variant's own fields account for
the most of the JSON object's keys instead of always taking the first.
@rsd-darshan
rsd-darshan requested a review from a team as a code owner June 26, 2026 11:59
@rsd-darshan

Copy link
Copy Markdown
Author

This resolves #483 and #514.

Both issues describe the same underlying bug: ResponseInputItemUnionParam registers EasyInputMessageParam, ResponseInputItemMessageParam, and ResponseOutputMessageParam all under the discriminator value "message", and the decoder picked whichever was registered first instead of the one that actually matches the payload (e.g. an output message echoed back into input).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant