Repository navigation
Description
Observed Behavior
Declarative workflows parse expressions and values with the host's culture.
On a host whose culture uses , as the decimal separator, such as de-DE or fr-FR:
=Max(1, 2)doesn't parse, and the workflow fails.ParseValueturns the string"3.14"into the number314on de-DE, and fails on fr-FR.
The same YAML works on en-US, so a workflow can pass on one machine and fail or give wrong values on another.
Expected Behavior
The same YAML gives the same result on every host, whatever its culture.
Steps to Reproduce
- Build the console app below against
Microsoft.Agents.AI.Workflows.Declarative. - Run it with
LC_ALL=en_US.UTF-8: it printsPrice is 3.14andMax is 2. - Run it with
LC_ALL=de_DE.UTF-8: it printsPrice is 314, then=Max(1, 2)fails to parse. - Run it with
LC_ALL=fr_FR.UTF-8:ParseValuefails withThe input string '3.14' was not in a correct format.
Minimal Reproduction
using System.Globalization;
using System.Runtime.CompilerServices;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Workflows;
using Microsoft.Agents.AI.Workflows.Declarative;
using Microsoft.Extensions.AI;
const string Yaml = """
kind: Workflow
trigger:
kind: OnConversationStart
id: repro
actions:
- kind: ParseValue
id: parse_price
variable: Local.Price
value: ="3.14"
valueType: Number
- kind: SendActivity
id: send_price
activity: "Price is {Local.Price}"
- kind: SetVariable
id: set_max
variable: Local.Max
value: =Max(1, 2)
- kind: SendActivity
id: send_max
activity: "Max is {Local.Max}"
""";
Console.WriteLine($"Culture: {CultureInfo.CurrentCulture.Name}");
Workflow workflow = DeclarativeWorkflowBuilder.Build<string>(new StringReader(Yaml), new DeclarativeWorkflowOptions(new NoAgentProvider()));
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, "start");
await foreach (WorkflowEvent evt in run.WatchStreamAsync())
{
switch (evt)
{
case MessageActivityEvent message:
Console.WriteLine($"Activity: {message.Message}");
break;
case ExecutorFailedEvent failed:
Console.WriteLine($"Executor failed: {failed.Data?.InnerException?.Message ?? failed.Data?.Message}");
break;
case WorkflowErrorEvent error:
Console.WriteLine($"Workflow error: {(error.Data as Exception)?.Message}");
break;
}
}
/// <summary>A provider for workflows that never call an agent.</summary>
internal sealed class NoAgentProvider : ResponseAgentProvider
{
public override Task<string> CreateConversationAsync(CancellationToken cancellationToken = default) =>
Task.FromResult(Guid.NewGuid().ToString("N"));
public override Task<ChatMessage> CreateMessageAsync(string conversationId, ChatMessage conversationMessage, CancellationToken cancellationToken = default) =>
Task.FromResult(conversationMessage);
public override Task<ChatMessage> GetMessageAsync(string conversationId, string messageId, CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public override IAsyncEnumerable<AgentResponseUpdate> InvokeAgentAsync(string agentId, string? agentVersion, string? conversationId, IEnumerable<ChatMessage>? messages, IDictionary<string, object?>? inputArguments, CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public override async IAsyncEnumerable<ChatMessage> GetMessagesAsync(string conversationId, int? limit = null, string? after = null, string? before = null, bool newestFirst = false, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
await Task.CompletedTask.ConfigureAwait(false);
yield break;
}
}Error Messages and Stack Traces
Culture: de-DE
Activity: Price is 314
Executor failed: Errors: Error 7-8: Operator erwartet. An dieser Stelle in der Formel wird ein Operator wie beispielsweise +, *, oder & erwartet.
Error 8-9: Unerwartete Zeichen. In der Formel werden Zeichen nicht erwartungsgemäß verwendet.
Error 9-9: Unerwartete Zeichen. Die Formel enthält „Eof“, es wird aber „ParenClose“ erwartet.
Workflow error: Error invoking handler for Microsoft.Agents.AI.Workflows.Declarative.Kit.ActionExecutorResult
Culture: fr-FR
Executor failed: The input string '3.14' was not in a correct format.
Workflow error: Error invoking handler for Microsoft.Agents.AI.Workflows.Declarative.Kit.ActionExecutorResult
Package Versions
Microsoft.Agents.AI.Workflows.Declarative: built from main (fad6929)
.NET Version
.NET 10.0
Operating System
macOS
Regression
Unknown
Additional Context
WorkflowExpressionEngine doesn't set ParserOptions.Culture, so Power Fx parses with the current culture.
ObjectExtensions.ConvertType, which ParseValue uses, calls double.Parse(s) and the like without a format provider.
TemplateExtensions.Format doesn't pass parser options either, but only tests call it (see #9495).
I tried setting ParserOptions.Culture to CultureInfo.InvariantCulture in WorkflowExpressionEngine and TemplateExtensions, and passing CultureInfo.InvariantCulture to those Parse calls.
With that, the repro prints Price is 3,14 and Max is 2 on de-DE and fr-FR.
The Declarative unit tests depend on the culture too.
On main, 72 of 1305 fail with LC_ALL=de_DE.UTF-8, and all pass with LC_ALL=en_US.UTF-8.
With the change above, en-US still passes and 20 still fail on de-DE:
- 11
EditTableExecutorTestcases callRecalcEngine.Evaldirectly in the test. - 7 tests expect US number or date formats, in
EntityExtractorTest,FormulaValueExtensionsTests, andObjectExtensionsTests. - 2
InvokeAzureAgentExecutorTestcases fail becauseIsBlankResponseMemberAccessFailurelooks for the English error textDeprecated use of '.'.
Power Fx localizes its errors, so on de-DE anexternalLoop.whenlike=Local.Result.IsResolvedthrows after a non-JSON reply instead of evaluating to false.
The Python package already runs Power Fx in en-US whatever the host culture (_POWERFX_EVAL_LOCALE in _declarative_base.py).
#4321 was the same English error-text problem there.
EntityExtractor also parses dates with DateTime.TryParse in the current culture, so on en-IN 12/25/2023 is invalid and 3 EntityExtractorTest cases fail.
That may be intended for user input, but the tests assume a US culture.
AI assistance: I used an AI coding assistant for the analysis, the repro, and this write-up.
Acknowledgements
- I searched existing issues and did not find a duplicate.
- I personally verified this behavior and the reproduction details are authentic.
- I will wait for explicit maintainer agreement before starting implementation of a non-trivial change.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
[-].NET: [Bug]: Declarative workflows fail or give wrong values on de-DE and fr-FR hosts[/-][+]Python: .NET: [Bug]: Declarative workflows fail or give wrong values on de-DE and fr-FR hosts[/+]github-actions commentedon Nov 3, 2026
🤖 Automated triage reproduction notes (agent-authored — trust but verify)
Agent analysis
Repro:
WorkflowExpressionEngine.cs::EvaluateScope/GetSensitiveReferencesrejectsMax(1, 2)under de-DE, whileObjectExtensions.cs::ConvertTypeconverts"3.14"to314. The trigger is evaluating declarative expressions or parsing numeric strings when the host uses comma decimal separators. Minimal repro: setCultureInfo.CurrentCulturetode-DE, evaluateNumberExpression.Expression("Max(1, 2)"), and convert"3.14"todouble.dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/PowerFx/WorkflowExpressionEngineTests.csmain@fad6929c[-]Python: .NET: [Bug]: Declarative workflows fail or give wrong values on de-DE and fr-FR hosts[/-][+].NET: [Bug]: Declarative workflows fail or give wrong values on de-DE and fr-FR hosts[/+]