[HB-8484] Synthesize named components for inline variants in discriminator mappings#3
Merged
Luc Fauvel (LucFauvel) merged 1 commit intoJun 12, 2026
Conversation
…ings
OpenAPI discriminator mappings can only reference named ($ref) schemas, so
unit variants and inline struct variants of internally tagged enums could
never appear in the mapping. Generated clients that dispatch deserialization
on the mapping (e.g. Kiota) then fail on those variants at parse time.
With the tagged_discriminator feature enabled, lift unit variants and
non-generic inline struct variants into synthesized `{Enum}{Variant}`
component schemas, reference them from the oneOf, register them via
ToSchema::schemas(), and add them to the discriminator mapping. Behavior
with the feature disabled is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR improves OpenAPI schema emission for internally tagged enums when the tagged_discriminator feature is enabled by ensuring discriminator mappings are complete even for variants that previously produced inline schemas (unit variants and inline struct variants). This prevents client generators that rely on discriminator mappings (e.g., Kiota) from failing to deserialize those variants.
Changes:
- Lift internally tagged unit variants into synthesized named component schemas (
{Enum}{Variant}), reference them via$refinoneOf, and include them in discriminator mappings. - Lift internally tagged inline struct variants into synthesized named components (skipping generic enums to avoid name collisions) so they can participate in discriminator mappings.
- Add/extend derive tests to assert both the emitted
oneOf/discriminator mapping and that synthesized components are registered with the expected tag-injected schema.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
utoipa-gen/src/component/schema/enums.rs |
Implements synthesis of named component schemas for internally tagged unit and inline struct variants to support complete discriminator mappings. |
utoipa-gen/tests/tagged_discriminator.rs |
Updates existing discriminator test expectations and adds a new test covering unit-variant synthesis + component registration assertions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Luc Fauvel (LucFauvel)
approved these changes
Jun 12, 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.
Problem
With the
tagged_discriminatorfeature, internally tagged enums emit aoneOfwith a discriminator — but only variants that are already$refs to named schemas get a mapping entry. OpenAPI discriminator mappings cannot reference inline schemas, so unit variants (e.g.Provider::None) and inline struct variants were silently left out of the mapping.Generated clients that dispatch deserialization on the mapping then fail at parse time on those variants. Concretely: the Hub C# Kiota client's
Provider.CreateFromDiscriminatorValuehas no"none"branch and falls through to a string-reader on a JSON object, throwing:This is the staging failure in
GetManyuser batches (any user without an SSO binding serializes as{"type":"none"}).Fix
When the
tagged_discriminatorfeature is enabled, for internally tagged enums:{Enum}{Variant}(a tag-only object schema), referenced via$reffrom theoneOf, registered throughToSchema::schemas(), and added to the discriminator mapping.For lucid's
Providerthis emitsoneOf [$ref ProviderNone, $ref ProviderOpenId]with a completenone/openIdmapping — no model changes needed in lucid. Spec-wide, this also fixesReauthenticationData,AuthenticatorDeviceAuthorizationStatus, andPasswordHashParams. Runtime serialization is untouched; only schema emission changes.Testing
derive_enum_tagged_discriminator_unit_varianttest mirroring lucid'sProvidershape, asserting both theoneOf/mapping output and that the synthesized component is registered with the correct tag-only schema.derive_enum_tagged_discriminator_complexfor the new inline-variant behavior, with a component-registration assertion.doc/openapi.json, generated the Kiota C# client from it, and confirmed{"type":"none"}and{"type":"openId",...}both deserialize correctly.Note: with the feature enabled, 3 additional stock snapshot tests in
schema_derive_testnow diverge (5 total, 2 predate this change) — expected, since the opt-in feature intentionally changes tagged-enum output.