Skip to content

[HB-8484] Synthesize named components for inline variants in discriminator mappings#3

Merged
Luc Fauvel (LucFauvel) merged 1 commit into
masterfrom
HB-8484/fix-discriminator-mappings
Jun 12, 2026
Merged

[HB-8484] Synthesize named components for inline variants in discriminator mappings#3
Luc Fauvel (LucFauvel) merged 1 commit into
masterfrom
HB-8484/fix-discriminator-mappings

Conversation

@metal-face

@metal-face metal-face (metal-face) commented Jun 11, 2026

Copy link
Copy Markdown

Problem

With the tagged_discriminator feature, internally tagged enums emit a oneOf with 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.CreateFromDiscriminatorValue has no "none" branch and falls through to a string-reader on a JSON object, throwing:

System.InvalidOperationException: The requested operation requires an element of type 'String', but the target element has type 'Object'.

This is the staging failure in GetMany user batches (any user without an SSO binding serializes as {"type":"none"}).

Fix

When the tagged_discriminator feature is enabled, for internally tagged enums:

  • Unit variants are lifted into a synthesized named component {Enum}{Variant} (a tag-only object schema), referenced via $ref from the oneOf, registered through ToSchema::schemas(), and added to the discriminator mapping.
  • Inline struct variants get the same treatment (skipped for generic enums, where instantiations would collide on the synthesized name).
  • Behavior with the feature disabled is unchanged (all 158 stock derive tests pass).

For lucid's Provider this emits oneOf [$ref ProviderNone, $ref ProviderOpenId] with a complete none/openId mapping — no model changes needed in lucid. Spec-wide, this also fixes ReauthenticationData, AuthenticatorDeviceAuthorizationStatus, and PasswordHashParams. Runtime serialization is untouched; only schema emission changes.

Testing

  • New derive_enum_tagged_discriminator_unit_variant test mirroring lucid's Provider shape, asserting both the oneOf/mapping output and that the synthesized component is registered with the correct tag-only schema.
  • Updated derive_enum_tagged_discriminator_complex for the new inline-variant behavior, with a component-registration assertion.
  • Validated end-to-end against lucid master: regenerated 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_test now diverge (5 total, 2 predate this change) — expected, since the opt-in feature intentionally changes tagged-enum output.

…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>
Copilot AI review requested due to automatic review settings June 11, 2026 20:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 $ref in oneOf, 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.

@LucFauvel Luc Fauvel (LucFauvel) merged commit ef9af1a into master Jun 12, 2026
1 check passed
@LucFauvel Luc Fauvel (LucFauvel) deleted the HB-8484/fix-discriminator-mappings branch June 12, 2026 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants