Skip to content

fix: map numeric scalar unions with a format to the numeric type - #7994

Open
FabienDehopre wants to merge 7 commits into
microsoft:mainfrom
FabienDehopre:fix/6541-numeric-string-union
Open

fix: map numeric scalar unions with a format to the numeric type#7994
FabienDehopre wants to merge 7 commits into
microsoft:mainfrom
FabienDehopre:fix/6541-numeric-string-union

Conversation

@FabienDehopre

Copy link
Copy Markdown

Fixes #6541

The problem

ASP.NET Core's OpenAPI 3.1 generator emits numeric members as a scalar union under System.Text.Json's default JsonNumberHandling.AllowReadingFromString:

"temperatureC": {
  "pattern": "^-?(?:0|[1-9]\\d*)$",
  "type": ["integer", "string"],
  "format": "int32"
}

KiotaBuilder.GetPrimitiveType computes the combined JsonSchemaType flags (Integer | String), which none of the switch arms match, so it returns null and the property degrades to UntypedNode — making these properties effectively unusable in the generated client. Since this is the out-of-the-box output of .NET 10's OpenAPI document generation, any ASP.NET Core API documented with the built-in generator hits this.

The fix

In GetPrimitiveType, when the schema type combines String with Integer or Number, strip the String flag before matching, so the numeric type (honoring format) wins. This follows the direction suggested in #6541 (comment): emit numbers as numbers only.

Scope is deliberately narrow:

  • Scalar unions without a format are untouched: they never reach this code path for model properties (IsExclusiveUnion() routes them to CreateComposedModelDeclaration, which generates the composed type wrapper as before). A test asserts this behavior is preserved.
  • Unions not involving a numeric type (["string", "boolean"], object unions, …) are untouched.
  • The fix is in the builder, so all target languages benefit.

Tests

  • New theory covering ["integer","string"] / ["number","string"] with int32, int64, double, float, and the nullable variants (Null flag), asserting the numeric type is generated.
  • Two cases asserting the no-format composed-type behavior is unchanged.
  • Full Kiota.Builder.Tests suite passes (2198 passed, 0 failed).
  • Verified end-to-end: regenerating a client from the exact document in Error when creating client for c# type int #6541's scenario now produces public int? TemperatureC { get; set; } instead of UntypedNode.

🤖 Generated with Claude Code

ASP.NET Core's OpenAPI 3.1 generator emits numeric members as
type ["integer"/"number", "string"] with a digit pattern under
System.Text.Json's default JsonNumberHandling.AllowReadingFromString.
GetPrimitiveType could not match the combined flags and returned null,
so such properties degraded to UntypedNode. Prefer the numeric type by
stripping the string flag when it is combined with integer or number.

Scalar unions without a format keep being generated as composed type
wrappers.

Fixes microsoft#6541

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@FabienDehopre
FabienDehopre requested a review from a team as a code owner July 27, 2026 12:52
Copilot AI review requested due to automatic review settings July 27, 2026 12:52
@FabienDehopre

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 updates Kiota’s schema-to-primitive mapping so OpenAPI 3.1 numeric “scalar unions” emitted by ASP.NET Core (e.g. type: ["integer","string"] with format: int32) resolve to numeric primitives instead of degrading to UntypedNode, improving usability of generated SDK models.

Changes:

  • Adjust KiotaBuilder.GetPrimitiveType to prefer numeric types over string when schema types combine numeric + string.
  • Add builder tests covering numeric/string unions with formats (and asserting existing no-format composed-type behavior for model properties).
  • Document the behavior change in CHANGELOG.md.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/Kiota.Builder/KiotaBuilder.cs Updates primitive type resolution logic for numeric+string scalar unions.
tests/Kiota.Builder.Tests/KiotaBuilderTests.cs Adds regression tests for numeric/string scalar unions (format and no-format cases).
CHANGELOG.md Notes the updated mapping behavior for numeric scalar unions with formats.

Comment thread src/Kiota.Builder/KiotaBuilder.cs
Comment thread tests/Kiota.Builder.Tests/KiotaBuilderTests.cs Outdated
baywet
baywet previously approved these changes Jul 27, 2026

@baywet baywet left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the contribution!

@baywet

baywet commented Jul 27, 2026

Copy link
Copy Markdown
Member

@FabienDehopre can you also apply the copilot suggestions please?

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 27, 2026 13:04
@FabienDehopre

Copy link
Copy Markdown
Author

Both copilot suggestions have been applied.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread src/Kiota.Builder/KiotaBuilder.cs
Copilot AI review requested due to automatic review settings July 27, 2026 13:09
baywet
baywet previously approved these changes Jul 27, 2026

@baywet baywet left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you for making the changes!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

…nion mapping

The validator warned that the string type would be used for
integer|string and number|string schemas with a numeric format, which
is no longer true now that GetPrimitiveType maps those unions to the
numeric type.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 27, 2026 13:17
FabienDehopre and others added 2 commits July 27, 2026 15:17
The test project does not enable nullable reference types, so the
string? parameter produced a CS8632 build warning.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comment thread src/Kiota.Builder/KiotaBuilder.cs
Comment thread src/Kiota.Builder/Validation/InconsistentTypeFormatPair.cs Outdated
Copilot AI review requested due to automatic review settings July 27, 2026 13:21
baywet
baywet previously approved these changes Jul 27, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/Kiota.Builder/Validation/InconsistentTypeFormatPair.cs:59

  • InconsistentTypeFormatPair warning text still says “the string type will be used”, but after the sanitizedType adjustment (and KiotaBuilder.GetPrimitiveType’s default numeric fallbacks), numeric|string unions with an unsupported format will map to a numeric type (e.g., Integerinteger) rather than string. This makes the warning misleading for the scenario this rule now targets.
            context.CreateWarning(nameof(InconsistentTypeFormatPair), $"The format {schema.Format} is not supported by Kiota for the type {sanitizedType} and the string type will be used.");

Gate the numeric|string union special-case on Kiota's supported numeric
formats so unions with a non-numeric format (uuid, date-time, ...) keep
the previous untyped fallback instead of silently mapping to a numeric
type. Also reword the InconsistentTypeFormatPair warning since the
fallback is no longer necessarily string.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 27, 2026 18:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

@FabienDehopre

Copy link
Copy Markdown
Author

@baywet I did push some more commits to comply to all the remaining copilot suggestions.
I think you need to re-approve the PR. Also, what's the next step before it gets merged? I see that some checks are failing (the idempotency tests) but it seems not related to this PR.

@FabienDehopre
FabienDehopre requested a review from baywet August 4, 2026 16:56
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.

Error when creating client for c# type int

3 participants