Variable Pool Falsy Value Handling#
Two related bugs caused valid falsy values (False, 0, empty strings) to be silently dropped during workflow variable resolution. Both share the same root cause β implicit Python truthiness checks used in place of explicit None checks β and were fixed in separate PRs.
Bug 1: VariablePool._get_nested_attribute() drops falsy nested values#
Affected component: api/core/workflow/entities/variable_pool.py (now in graphon external package)
When resolving a nested attribute on an ObjectSegment (e.g., some_object.count where count = 0), the original _get_nested_attribute() returned None for any falsy value because it relied on obj.get(attr) whose falsy return was indistinguishable from a missing key .
Fix (PR #26155): Replace the single isinstance guard with a two-condition check:
# Before
if not isinstance(obj, dict):
return None
return obj.get(attr)
# After
if not isinstance(obj, dict) or attr not in obj:
return None
return variable_factory.build_segment(obj.get(attr))
The attr not in obj membership test explicitly distinguishes "key is absent" from "key exists with a falsy value." Additionally, variable_factory.build_segment() was updated to short-circuit when the input is already a Segment instance , preventing double-wrapping during extraction.
Tests covering None, "", 0, and False were added at api/tests/unit_tests/core/workflow/entities/test_variable_pool.py .
Bug 2: WorkflowEntry.mapping_user_inputs_to_variable_pool() drops falsy user inputs#
Affected component: api/core/workflow/workflow_entry.py β used during single-step (debugger) node execution.
The input resolution falls back from a full key (node_id.variable_key) to a short key (variable_key). The fallback was gated on a truthiness check :
input_value = user_inputs.get(node_variable)
if not input_value: # BUG: also triggers for False, 0, ""
input_value = user_inputs.get(node_variable_key)
if input_value is None:
continue
When user_inputs["node.enabled"] = False, not input_value is True, so the code falls through to the short-key lookup (user_inputs.get("enabled")). If that key is also absent, input_value becomes None and the continue skips writing the value to the pool β even though the caller explicitly provided False .
Fix (PR #25908): Change the fallback guard to an explicit None check:
input_value = user_inputs.get(node_variable)
if input_value is None: # FIXED: only falls back when key is truly absent
input_value = user_inputs.get(node_variable_key)
The current mapping_user_inputs_to_variable_pool() implementation uses the is None fallback pattern alongside an is None guard before continue . Note that a separate variable_pool.get() truthiness guard at line 563 still uses not variable_pool.get(variable_selector), which may silently pass for pools containing falsy values β a remaining risk area .
The Recurring Pattern#
| Anti-pattern | Correct pattern | What it fixes |
|---|---|---|
if not value: | if value is None: | Keeps False, 0, "" from being treated as absent |
obj.get(key) truthiness | key not in obj + obj.get(key) | Distinguishes missing key from falsy value |
Both bugs recur easily because Python developers habitually use truthiness checks as "absent" guards. If you encounter a workflow where 0, False, or "" values disappear mid-execution, audit any if not value: or if value: guard that gates variable pool writes or reads.
β οΈ Regression risk: Issue #38963 confirmed that as of commit
40df83de, line 579 ofworkflow_entry.pystill containedif not input_value:β either a regression or a missed code path from PR #25908 .
Key Source References#
| File | Purpose |
|---|---|
api/core/workflow/workflow_entry.py | mapping_user_inputs_to_variable_pool() β falsy input fallback logic |
api/core/workflow/entities/variable_pool.py | _get_nested_attribute() β nested attribute resolution (moved to graphon package) |
api/factories/variable_factory.py | build_segment() β Segment factory with isinstance(value, Segment) guard |
| PR #26155 | Fix _get_nested_attribute falsy nested value bug |
| PR #25908 | Fix single-step variable loading falsy input bug |