Repository navigation
.NET: [Bug]: Agent Skill throws "System.InvalidOperationException" #7989
Description
Description
I'm exploring the examples of the Microsoft Agent Framework and have a question or maybe found a problem or issue. ;)
When I execute the example Agent_Step03_ClassBasedSkills using my local AI (Model qwen3.8-27b) with the OpenAI API, the Agent returns something like this:
Converting units with class-based skills
------------------------------------------------------------
Agent:
The conversion script isn't working, so I calculated these using the conversion table's formula (result = value × factor):
## Marathon: 26.2 miles ␦ kilometers
- **26.2 × 1.60934 = 42.16 km** (42.164708, rounded)
So a marathon is about **42.16 kilometers** - commonly rounded to 42.2 km.
## 75 kilograms ␦ pounds
- **75 × 2.20462 = 165.35 lbs** (165.3465, rounded)
So 75 kilograms is about **165.35 pounds**.
The important part is "The conversion script isn't working, so I calculated these using the conversion table's formula (result = value × factor)"
In the output windows I see a couple of exceptions like this:
Exception thrown: 'System.InvalidOperationException' in Microsoft.Agents.AI.dll
Inline skill scripts expect arguments as a JSON object but received a JSON element of kind 'String'.
Debugging further gives me the AgentInlineSkillScript and there I found
private static AIFunctionArguments ConvertToFunctionArguments(JsonElement? arguments)
{
if (arguments is null ||
arguments.Value.ValueKind == JsonValueKind.Null ||
arguments.Value.ValueKind == JsonValueKind.Undefined)
{
return [];
}
if (arguments.Value.ValueKind != JsonValueKind.Object)
{
throw new InvalidOperationException(
$"Inline skill scripts expect arguments as a JSON object but received a JSON element of kind '{arguments.Value.ValueKind}'.");
}
var dict = new Dictionary<string, object?>();
foreach (var property in arguments.Value.EnumerateObject())
{
dict[property.Name] = property.Value;
}
return new AIFunctionArguments(dict);
}
So, no matter what the LLM is using as parameter calling the skill script, as long as this is no JSON-Object, this function throws an exception.
So my question is:
how can I call the skill with the two double values as expected, so that the LLM can use the skill and does not run into a failure?
Code Sample
/// <summary>
/// Converts a value by the given factor.
/// </summary>
[AgentSkillScript("convert")]
[Description("Multiplies a value by a conversion factor and returns the result as JSON.")]
private static string ConvertUnits(double value, double factor)
{
double result = Math.Round(value * factor, 4);
return JsonSerializer.Serialize(new { value, factor, result });
}Error Messages / Stack Traces
Package Versions
Microsoft.Agents.AI: 1.20.0; Microsoft.Agents.AI.OpenAI: 1.20.0;
.NET Version
.NET 10
Additional Context
No response
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
github-actions commentedon Sep 1, 2026
👋 Hi s-kip — thanks for the report!
Your exception explicitly says the model supplied
argumentsas a JSONString, while the loaded skill schema requires an object. The correctrun_skill_scriptpayload is{"skillName":"unit-converter","scriptName":"convert","arguments":{"value":26.2,"factor":1.60934}}; with that shape, your two values produce42.1647. Your local model appears to be quoting/stringifying theargumentsobject instead of emitting it directly.If you still believe there is a framework issue here, please reply with the exact import/class or method you are using, the version, and a minimal snippet that shows the failure. 🙏
s-kip commentedon Sep 1, 2026
I debugged the
ConvertToFunctionArgumentsof theAgentInlineSkillScript.csand this is an exmaple of the parameterargumentsthat was used:"{"value": 26.2, "factor": 1.60934}"So is the LLM the problem, because it uses the wrong values for the parameter
arguments?If yes, what can I do to "tell" my LLM what to use instead?
atty57 commentedon Sep 1, 2026
Your debugging is correct — the model is the immediate cause. Your local model is emitting
argumentsdouble-encoded: a JSON string containing{"value": 26.2, "factor": 1.60934}rather than the object itself. Smaller/local models do this fairly often; GPT-class models usually don't.The
run_skill_scripttool declaresargumentsasJsonElement?(AgentSkillsProvider.cs), which gives an unconstrained schema, so nothing at the tool-call level tells the model it must be an object — and the default marshaler then rejects anything that isn't one.You don't have to patch the framework though: every skill type accepts an
argumentMarshaler, includingAgentClassSkill<TSelf>. Adding one to the sample skill makes it tolerate the stringified form:If you'd also like to nudge the model in the prompt,
AgentSkillsProviderOptions.SkillsInstructionPromptreplaces the default skills instruction block — you can append something like "passargumentstorun_skill_scriptas a JSON object, never as a JSON-encoded string". Note that this needs the collection constructor rather than theparamsone used in the sample:Expect that to help but not be fully reliable on a small local model; the marshaler is the deterministic fix.
For the maintainers: it may be worth having the default marshaler unwrap a JSON string that contains an object (a handful of lines), since double-encoded tool arguments are common with OpenAI-compatible local models, and mentioning the
argumentMarshalerescape hatch in the exception message — right now nothing points users to it.s-kip commentedon Sep 2, 2026
Thx Atharva Vichare (@atty57) for clarifying on this.
I tried to set the
SkillInstructionPrompt, without success.But it worked with the custom marshaler you wrote 👍
In my opinion, it would be great if the default marshaler handles this automatically.
Or the exception should contain a hint to the solution with the custom marshaler.
Because,as you already mentioned, nothing points me to this solution.
SergeyMenshykh commentedon Sep 7, 2026
s-kip, thanks for reporting this issue. Agent Framework should not automatically “heal” malformed JSON, as guessing the intended structure can be ambiguous, hide model/provider interoperability problems, and produce unexpected behavior. Providers should emit arguments that conform to the declared tool schema, while applications can use a custom argument marshaler when model-specific normalization is required.
We’ve addressed your suggestion by updating the exception message to point users to the custom argument marshaler.