Skip to content

Identify the parameter in AIFunctionFactory argument conversion errors - #7779

Open
mauri0686 wants to merge 1 commit into
dotnet:mainfrom
mauri0686:improve-argument-conversion-error
Open

mauri0686 wants to merge 1 commit into
dotnet:mainfrom
mauri0686:improve-argument-conversion-error

Conversation

@mauri0686

@mauri0686 mauri0686 commented Sep 24, 2026 •

Copy link
Copy Markdown

Contributes to #7626.

Following the feedback on #7630, this does not add any tolerance for double-encoded arguments. It only makes the failure easier to diagnose and correct.

Change

When a JsonElement, JsonDocument or JsonNode argument cannot be deserialized to its parameter type, the parameter marshaller in AIFunctionFactory now rethrows a JsonException that names the parameter. When a JSON string was supplied where the parameter's contract is an object, dictionary or collection, the message also says so and suggests passing the JSON value directly.

The original message, Path, LineNumber, BytePositionInLine and the original exception (as InnerException) are preserved. Binding behavior, the exception type and the public API are unchanged. No hint is added for types whose contract is a JSON primitive (for example Guid or DateTimeOffset), since a string is a valid representation for those.

For the repro in the issue, the message is now:

The value provided for parameter 'input' could not be converted to the parameter's type. A JSON string was provided where a JSON object was expected; if the string contains serialized JSON, provide the JSON value directly instead of as a string. The JSON value could not be converted to Input. Path: $ | LineNumber: 0 | BytePositionInLine: 59.

Not included

With the default IncludeDetailedErrors = false, FunctionInvokingChatClient still sends Error: Function failed. to the model. Surfacing binding errors in that mode requires distinguishing them from exceptions thrown by the function body, which means new API, so I raised it on the issue instead.

Tests

New tests in AIFunctionFactoryTest cover JSON string arguments bound to object and collection parameters (via JsonElement, JsonDocument and JsonNode), and mismatches that must not get the hint (non-string values, Guid). All of them fail without the change.

Microsoft.Extensions.AI.Tests and Microsoft.Extensions.AI.Abstractions.Tests pass on net8.0, net9.0, net10.0 and net472.

Microsoft Reviewers: Open in CodeFlow

…ument

When a JsonElement, JsonDocument or JsonNode argument cannot be deserialized
to its parameter type, the JsonException thrown by the parameter marshaller
now names the parameter. If a JSON string was supplied where a JSON object or
array was expected (for example a double-encoded tool call argument), the
message says so and suggests passing the JSON value directly.

The exception type, path information and original exception (as
InnerException) are preserved, and binding behavior is unchanged.

Contributes to dotnet#7626.
@mauri0686

Copy link
Copy Markdown
Author

@dotnet-policy-service agree

@dotnet-comment-bot

Copy link
Copy Markdown
Collaborator

‼️ Found issues ‼️

Project Coverage Type Expected Actual
Microsoft.Extensions.Diagnostics.Testing Line 99 98.65 🔻
Microsoft.Extensions.Telemetry Line 93 92.64 🔻
Microsoft.Extensions.AI.OpenAI Line 75 68.32 🔻
Microsoft.Extensions.AI.OpenAI Branch 75 57.59 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Line 75 4.46 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Branch 75 0 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Line 99 96.03 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Branch 99 92.76 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes Line 99 97.73 🔻
Microsoft.Extensions.ServiceDiscovery.Dns Line 75 69.93 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Line 75 42.11 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Branch 75 42.86 🔻
Microsoft.Extensions.ServiceDiscovery Line 75 67.21 🔻
Microsoft.Extensions.ServiceDiscovery Branch 75 71.43 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Line 75 73.85 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Branch 75 70 🔻
Microsoft.Extensions.VectorData.Abstractions Line 75 37.39 🔻
Microsoft.Extensions.VectorData.Abstractions Branch 75 22.73 🔻

🎉 Good job! The coverage increased 🎉
Update MinCodeCoverage in the project files.

Project Expected Actual
Microsoft.Extensions.Http.Diagnostics 94 95
Microsoft.Gen.BuildMetadata 97 100
Microsoft.Gen.MetadataExtractor 57 73
Microsoft.Gen.MetricsReports 67 69
Microsoft.Extensions.AI.Abstractions 82 86
Microsoft.Extensions.AI.Evaluation.NLP 0 78
Microsoft.Extensions.Caching.Hybrid 82 84
Microsoft.Extensions.DataIngestion 75 89
Microsoft.Extensions.DataIngestion.Markdig 75 90
Microsoft.Extensions.Http.Resilience 97 100

Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1610124&view=codecoverage-tab

@github-actions github-actions Bot added the area-ai Microsoft.Extensions.AI libraries label Sep 24, 2026
@mauri0686

Copy link
Copy Markdown
Author

@eiriktsarpalis when you have a moment, could you take a look? It follows your feedback on #7626: the marshaller stays strict, and the JsonException now names the parameter and points out when a JSON string arrived where an object was expected, so the model gets something it can correct. The coverage bot flags projects this change doesn't touch.

Note

Drafted with AI assistance (Claude Code) and reviewed by me.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-ai Microsoft.Extensions.AI libraries

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants