microsoft / microsoft/kiota

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

Open
#7,573 2 comments 3 reactions 2 assignees Claimed by @gavinbarron View on GitHub
Dominant language
C#
Stars
3.8k
Forks
333
Avg merge
16h 29m
Merged PRs (30d)
116

Description

## 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:
```yaml
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:
```json
{
"effectType": "addLoyaltyPoints",
"props": {
"name": "Product registered",
"value": 75,
"programId": 37,
"transactionUUID": "abc-123"
}
}
```

After Kiota deserialization:
```csharp
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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.