Skip to content

Python: Fix PowerFx eval crash on non-English system locales by setting CurrentUICulture to en-US#4408

Merged
moonbox3 merged 3 commits intomicrosoft:mainfrom
moonbox3:agent/fix-4321-1
Mar 4, 2026
Merged

Python: Fix PowerFx eval crash on non-English system locales by setting CurrentUICulture to en-US#4408
moonbox3 merged 3 commits intomicrosoft:mainfrom
moonbox3:agent/fix-4321-1

Conversation

@moonbox3
Copy link
Contributor

@moonbox3 moonbox3 commented Mar 3, 2026

Motivation and Context

On non-English system locales, PowerFx emits localized error messages for undefined variables (e.g., Italian instead of English). The existing error-handling guards only match English strings like "isn't recognized" and "Name isn't valid", so localized messages fall through and crash the workflow.

Fixes #4321

Description

The root cause is that CurrentUICulture controls the language of .NET error messages, but only CurrentCulture was being set to en-US before calling engine.eval. This fix saves and overrides CurrentUICulture to en-US alongside CurrentCulture, ensuring PowerFx error messages are always in English and match the existing string guards. Both cultures are restored in the finally block. A regression test simulates a non-English UI culture (it-IT) and verifies that undefined variable references return None instead of raising.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

Note: PR autogenerated by moonbox3's agent

On non-English systems, CultureInfo.CurrentUICulture causes PowerFx to
emit localized error messages. The existing ValueError guard only matches
English strings ("isn't recognized", "Name isn't valid"), so undefined
variable errors crash instead of returning None gracefully.

Fix: save and restore CurrentUICulture alongside CurrentCulture before
calling engine.eval(), ensuring error messages are always in English.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 3, 2026 03:17
Copy link
Contributor Author

@moonbox3 moonbox3 left a comment

Choose a reason for hiding this comment

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

Automated Code Review

Reviewers: 3 | Confidence: 89%

✓ Correctness

The diff correctly saves and restores CurrentUICulture alongside CurrentCulture before calling engine.eval(), ensuring PowerFx error messages are always in English so the downstream string-matching error handlers work on non-English systems. The finally block properly restores both culture values even when exceptions propagate to the outer except ValueError. The regression test is well-structured and mirrors the existing test patterns. No correctness issues found.

✓ Security Reliability

The diff correctly extends the existing culture save/restore pattern to also cover CurrentUICulture, preventing localized PowerFx error messages from bypassing English string guards. The finally block properly restores both culture values on all exit paths. No new security or reliability issues are introduced; the pre-existing thread-safety concern around mutating global/thread-local culture state is not worsened by this change.

✓ Test Coverage

The diff adds CurrentUICulture handling alongside CurrentCulture in the PowerFx eval path and includes a well-structured regression test that sets a non-English UI culture and verifies undefined variables still return None. The test directly exercises the bug scenario. However, there is no assertion verifying that CurrentUICulture is properly restored after eval() returns, which is the other half of the production-code change (the finally block). Without that, a regression in the cleanup path would go undetected.

Suggestions

  • The mutation of CultureInfo.CurrentCulture and CultureInfo.CurrentUICulture is not thread-safe if multiple threads call eval concurrently. This is a pre-existing concern not introduced by this diff, but worth noting for future hardening (e.g., using a lock around the eval call).
  • Add an assertion after state.eval() to verify that CurrentUICulture is restored to the pre-eval value (e.g., 'it-IT'). This would cover the finally-block restoration logic in the production code and catch future regressions in cleanup.
  • Consider adding a parallel test (or extending this one) that exercises a successful eval (not just the undefined-variable error path) under a non-English UI culture, to confirm the culture-swap works for normal evaluation too.

Automated review by moonbox3's agents

@markwallace-microsoft
Copy link
Member

markwallace-microsoft commented Mar 3, 2026

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/declarative/agent_framework_declarative/_workflows
   _declarative_base.py3893890%44, 47, 134, 212, 226, 240, 251, 268, 407, 435, 518–520, 522–524, 526, 529, 536, 562, 586–590, 592–600, 621–622, 624–625
TOTAL22226273987% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
4718 247 💤 0 ❌ 0 🔥 1m 19s ⏱️

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a locale-dependent crash in the declarative PowerFx evaluator by ensuring .NET UI culture is forced to English during evaluation, so existing (English) error-string guards behave consistently across non-English systems.

Changes:

  • In DeclarativeWorkflowState.eval(), temporarily sets CultureInfo.CurrentUICulture to en-US alongside CurrentCulture and restores both afterward.
  • Adds a regression test that simulates a non-English UI culture (it-IT) and verifies undefined variables return None instead of raising.

Reviewed changes

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

File Description
python/packages/declarative/agent_framework_declarative/_workflows/_declarative_base.py Forces CurrentUICulture to en-US during PowerFx engine.eval() to prevent localized error messages from bypassing the undefined-variable guard.
python/packages/declarative/tests/test_powerfx_yaml_compatibility.py Adds a regression test for non-English UI cultures to ensure undefined variable references are handled gracefully.

moonbox3 and others added 2 commits March 3, 2026 12:21
Cache CultureInfo("en-US") in a local variable instead of instantiating
it twice per eval() call, as suggested in PR review.

Fixes microsoft#4321

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assert that the production code's finally-block correctly restores
CurrentUICulture to it-IT after eval returns, covering future
regressions where the culture could leak.

The CultureInfo caching suggestion (comment #2) was already
implemented in the production code.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@moonbox3 moonbox3 self-assigned this Mar 3, 2026
@moonbox3 moonbox3 added this pull request to the merge queue Mar 4, 2026
Merged via the queue into microsoft:main with commit 4dc20c6 Mar 4, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: Declarative: PowerFx undefined-variable errors crash on non-English system locales

5 participants