Repository navigation
Description
Observed Behavior
A SetValue action that uses variable: instead of path: passes build() validation, then does nothing at run time. The target variable stays unset and there is no error or warning.
The builder accepts variable on purpose. ACTION_ALTERNATE_FIELDS has "SetValue.path": ["variable"] (_declarative_builder.py:99) and test_setvalue_accepts_alternate_variable_field checks that this builds. But SetValueExecutor only reads path (_executors_basic.py:56), so the write is skipped.
Expected Behavior
SetValue with variable: Local.b (or variable: {path: Local.b}) sets Local.b, same as path: Local.b does. SetVariable already reads both shapes through _get_variable_path.
Steps to Reproduce
- Build a workflow with
kind: SetValue,variable: Local.b,value: from variable. - Run it.
- Read
Local.b. It isNone.
Minimal Reproduction
No API keys or PowerFx needed. It reads the state from the last checkpoint.
"""Repro: declarative SetValue with `variable:` builds fine but writes nothing.
Runs the real workflow (no PowerFx, no API keys) and reads the declarative
state from the last checkpoint.
"""
import asyncio
import agent_framework_declarative
from agent_framework import InMemoryCheckpointStorage
from agent_framework_declarative._workflows._declarative_base import DECLARATIVE_STATE_KEY
from agent_framework_declarative._workflows._factory import WorkflowFactory
print("agent_framework_declarative from:", agent_framework_declarative.__file__)
YAML = """
kind: Workflow
name: setvalue_variable
actions:
- kind: SetValue
id: with_path
path: Local.a
value: from path
- kind: SetValue
id: with_variable
variable: Local.b
value: from variable
- kind: SetValue
id: with_nested_variable
variable:
path: Local.c
value: from nested variable
"""
async def main() -> None:
storage = InMemoryCheckpointStorage()
workflow = WorkflowFactory(checkpoint_storage=storage).create_workflow_from_yaml(YAML)
await workflow.run({})
checkpoints = await storage.list_checkpoints(workflow_name=workflow.name)
last = max(checkpoints, key=lambda c: c.timestamp)
local = last.state[DECLARATIVE_STATE_KEY]["Local"]
print("Local.a =", repr(local.get("a")))
print("Local.b =", repr(local.get("b")))
print("Local.c =", repr(local.get("c")))
asyncio.run(main())Output on main (cae4955):
agent_framework_declarative from: python/packages/declarative/agent_framework_declarative/__init__.py
Local.a = 'from path'
Local.b = None
Local.c = None
Local.a uses path: and works. Local.b and Local.c use variable: and are never set.
Error Messages and Stack Traces
None. That's the problem, it fails silently.
Package Versions
agent-framework-core 1.22.0, agent-framework-declarative 1.3.0 (main at cae4955)
Python Version
3.12.13
Operating System
macOS 26.6.2
Regression
No. The alias and the executor have been out of sync since the declarative runtime landed in #2815.
Additional Context
Root cause: python/packages/declarative/agent_framework_declarative/_workflows/_executors_basic.py:56
path = self._action_def.get("path")Proposed fix, one line: path = self._action_def.get("path") or _get_variable_path(self._action_def). path still wins when both are set. I have it ready with a test and can open the PR.
The other choice would be to drop the variable alternate from the builder so this fails at build time. I went with honoring it, since the builder and its test already treat variable as valid, and .NET authors write variable: on SetVariable.
AI assistance: I used an AI assistant to help find and analyze this bug. I ran the repro and checked the output myself.
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
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
[-]Python: [Bug]: Declarative SetValue with `variable:` builds fine but never writes the value[/-][+].NET: Python: [Bug]: Declarative SetValue with `variable:` builds fine but never writes the value[/+]github-actions commentedon Oct 15, 2026
🤖 Automated triage reproduction notes (agent-authored — trust but verify)
Agent analysis
Repro:
python/packages/declarative/agent_framework_declarative/_workflows/_executors_basic.py::SetValueExecutor.handle_actionat line 56 skips writes whenSetValuesuppliesvariableas either a string or{path: ...}. The builder accepts both shapes, but the executor observes nopath. Minimal repro: executeSetValueExecutorwith either variable shape and assert the target state value; it remainsNone.python/packages/declarative/tests/test_graph_coverage.py::TestBasicExecutorsCoverage::test_set_value_executor_with_variable1.3.01.3.0