Skip to content

C# oneOf deserialization silently loses data when no discriminator is defined #7573

@davidwinslowtech

Description

@davidwinslowtech

Description

When an OpenAPI spec defines a oneOf composed type without a discriminator, Kiota generates an IComposedTypeWrapper class with properties for each concrete type. At runtime, deserialization silently produces null values for all typed properties -- the JSON data is effectively lost.

Steps to reproduce

OpenAPI spec:

Effect:
  allOf:
    - \$ref: '#/components/schemas/EffectEntity'
    - type: object
      properties:
        props:
          oneOf:
            - \$ref: '#/components/schemas/AddLoyaltyPointsEffectProps'
            - \$ref: '#/components/schemas/DeductLoyaltyPointsEffectProps'
            - \$ref: '#/components/schemas/TriggerWebhookEffectProps'
            # ... ~30 more types

The JSON response from the API:

{
  "effectType": "addLoyaltyPoints",
  "props": {
    "name": "Product registered",
    "value": 75,
    "programId": 37,
    "transactionUUID": "abc-123"
  }
}

After Kiota deserialization:

effect.Props                              // not null (Effect_props wrapper)
effect.Props.AddLoyaltyPointsEffectProps  // null
effect.Props.DeductLoyaltyPointsEffectProps // null
// All typed properties are null -- data is lost
// AdditionalData on Effect_props is not available (IComposedTypeWrapper doesn't implement IAdditionalDataHolder)

Expected behavior

At minimum, one of:

  1. The data should be preserved in AdditionalData on the composed type wrapper so consumers can access it
  2. Kiota should attempt to populate all concrete types with matching fields (best-effort deserialization)
  3. A warning should be emitted at generation time that oneOf without discriminator will not deserialize correctly in C#

Actual behavior

All typed properties on the IComposedTypeWrapper are null. The JSON data is silently discarded with no error, warning, or fallback. There is no way to access the original data.

Workaround

We replaced the oneOf with a single flat schema containing all fields as optional properties, then regenerated the client. This works but loses the type safety that oneOf is meant to provide.

Environment

  • Kiota version: 1.29.0
  • Language: C#
  • .NET version: 9.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Needs Triage 🔍

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions