Unexpected behaviour of Variable Aggregator on different branches
Self Checks
- [x] This is only for bug report, if you would like to ask a question, please head to Discussions.
- [x] I have searched for existing issues search for existing issues, including closed ones.
- [x] I confirm that I am using English to submit this report (我已阅读并同意 Language Policy).
- [x] [FOR CHINESE USERS] 请务必使用英文提交 Issue,否则会被关闭。谢谢!:)
- [x] Please do not modify this template :) and fill in all the required fields.
Dify version
1.4.1
Cloud or Self Hosted
Self Hosted (Docker)
Steps to reproduce
I found a strange behaviour in my chatflow. I want to search different knowledge base depends on different event types and use Variable Aggregator to aggregate corresponding knowledge. But the Variable Aggregator are skipped like this:
I made a minimal reproduction chatflow like this:
The Conditional Branch node would go into different branches depending on user's input from choices [1,2,3]. The Code Execution nodes 1A, 1B, 2A, 2B are used to generate its corresponding strings like "1a", "1b", "2a" and "2b". The Variable Aggregator nodes A and B where the bug lies aim to aggregate the results with postfix "a" and "b". The Answer node would output the results from the both Variable Aggregator nodes directly.
Here is the minium reproduction DSL for debugging:
DSL content
app:/
description: ''
icon: 🤖
icon_background: '#FFEAD5'
mode: advanced-chat
name: bugtest-并行
use_icon_as_answer_icon: false
dependencies: []
kind: app
version: 0.3.0
workflow:
conversation_variables: []
environment_variables: []
features:
file_upload:
allowed_file_extensions:
- .JPG
- .JPEG
- .PNG
- .GIF
- .WEBP
- .SVG
allowed_file_types:
- image
allowed_file_upload_methods:
- local_file
- remote_url
enabled: false
fileUploadConfig:
audio_file_size_limit: 50
batch_count_limit: 5
file_size_limit: 15
image_file_size_limit: 10
video_file_size_limit: 100
workflow_file_upload_limit: 10
image:
enabled: false
number_limits: 3
transfer_methods:
- local_file
- remote_url
number_limits: 3
opening_statement: ''
retriever_resource:
enabled: true
sensitive_word_avoidance:
enabled: false
speech_to_text:
enabled: false
suggested_questions: []
suggested_questions_after_answer:
enabled: false
text_to_speech:
enabled: false
language: ''
voice: ''
graph:
edges:
- data:
isInLoop: false
sourceType: start
targetType: if-else
id: 1748962309200-source-1748962316650-target
selected: false
source: '1748962309200'
sourceHandle: source
target: '1748962316650'
targetHandle: target
type: custom
zIndex: 0
- data:
isInLoop: false
sourceType: if-else
targetType: code
id: 1748962316650-true-1748962370039-target
selected: false
source: '1748962316650'
sourceHandle: 'true'
target: '1748962370039'
targetHandle: target
type: custom
zIndex: 0
- data:
isInLoop: false
sourceType: variable-aggregator
targetType: answer
id: 1748962354160-source-1748962443930-target
selected: false
source: '1748962354160'
sourceHandle: source
target: '1748962443930'
targetHandle: target
type: custom
zIndex: 0
- data:
isInLoop: false
sourceType: if-else
targetType: code
id: 1748962316650-true-17489624177180-target
selected: false
source: '1748962316650'
sourceHandle: 'true'
target: '17489624177180'
targetHandle: target
type: custom
zIndex: 0
- data:
isInLoop: false
sourceType: if-else
targetType: code
id: 1748962316650-f7644790-79ca-4c3f-b690-b85450789c77-17489625222390-target
selected: false
source: '1748962316650'
sourceHandle: f7644790-79ca-4c3f-b690-b85450789c77
target: '17489625222390'
targetHandle: target
type: custom
zIndex: 0
- data:
isInLoop: false
sourceType: if-else
targetType: code
id: 1748962316650-f7644790-79ca-4c3f-b690-b85450789c77-17489625325210-target
selected: false
source: '1748962316650'
sourceHandle: f7644790-79ca-4c3f-b690-b85450789c77
target: '17489625325210'
targetHandle: target
type: custom
zIndex: 0
- data:
isInLoop: false
sourceType: code
targetType: variable-aggregator
id: 1748962370039-source-1748962354160-target
selected: false
source: '1748962370039'
sourceHandle: source
target: '1748962354160'
targetHandle: target
type: custom
zIndex: 0
- data:
isInLoop: false
sourceType: code
targetType: variable-aggregator
id: 17489625222390-source-1748962354160-target
selected: false
source: '17489625222390'
sourceHandle: source
target: '1748962354160'
targetHandle: target
type: custom
zIndex: 0
- data:
isInLoop: false
sourceType: code
targetType: variable-aggregator
id: 17489624177180-source-17489625685610-target
selected: false
source: '17489624177180'
sourceHandle: source
target: '17489625685610'
targetHandle: target
type: custom
zIndex: 0
- data:
isInLoop: false
sourceType: code
targetType: variable-aggregator
id: 17489625325210-source-17489625685610-target
selected: false
source: '17489625325210'
sourceHandle: source
target: '17489625685610'
targetHandle: target
type: custom
zIndex: 0
- data:
isInLoop: false
sourceType: variable-aggregator
targetType: answer
id: 17489625685610-source-1748962443930-target
selected: false
source: '17489625685610'
sourceHandle: source
target: '1748962443930'
targetHandle: target
type: custom
zIndex: 0
nodes:
- data:
desc: ''
selected: false
title: 开始
type: start
variables: []
height: 54
id: '1748962309200'
position:
x: 80
y: 282
positionAbsolute:
x: 80
y: 282
sourcePosition: right
targetPosition: left
type: custom
width: 244
- data:
cases:
- case_id: 'true'
conditions:
- comparison_operator: is
id: 5ddebef1-e5cf-4043-8101-1dd0b9c7a472
value: '1'
varType: string
variable_selector:
- sys
- query
id: 'true'
logical_operator: and
- case_id: f7644790-79ca-4c3f-b690-b85450789c77
conditions:
- comparison_operator: is
id: 274c03d5-ffec-471b-a11d-9c14c5c8593d
value: '2'
varType: string
variable_selector:
- sys
- query
id: f7644790-79ca-4c3f-b690-b85450789c77
logical_operator: and
- case_id: ea89f090-bd49-467e-980c-943312d36439
conditions:
- comparison_operator: is
id: 73e44731-75c7-4a38-ae73-29bacfa247e8
value: '3'
varType: string
variable_selector:
- sys
- query
id: ea89f090-bd49-467e-980c-943312d36439
logical_operator: and
desc: ''
selected: false
title: 条件分支
type: if-else
height: 222
id: '1748962316650'
position:
x: 386
y: 282
positionAbsolute:
x: 386
y: 282
selected: false
sourcePosition: right
targetPosition: left
type: custom
width: 244
- data:
desc: ''
output_type: string
selected: false
title: a
type: variable-aggregator
variables:
- - '1748962370039'
- result
- - '17489625222390'
- result
height: 131
id: '1748962354160'
position:
x: 1238
y: 203
positionAbsolute:
x: 1238
y: 203
selected: false
sourcePosition: right
targetPosition: left
type: custom
width: 244
- data:
code: "\ndef main(arg1: str) -> dict:\n return {\n \"result\": \"\
1a\",\n }\n"
code_language: python3
desc: ''
outputs:
result:
children: null
type: string
selected: true
title: 1a
type: code
variables:
- value_selector:
- sys
- query
variable: arg1
height: 54
id: '1748962370039'
position:
x: 729
y: 175
positionAbsolute:
x: 729
y: 175
selected: true
sourcePosition: right
targetPosition: left
type: custom
width: 244
- data:
code: "\ndef main(arg1: str) -> dict:\n return {\n \"result\": \"\
1b\",\n }\n"
code_language: python3
desc: ''
outputs:
result:
children: null
type: string
selected: false
title: 1b
type: code
variables:
- value_selector:
- sys
- query
variable: arg1
height: 54
id: '17489624177180'
position:
x: 729
y: 267
positionAbsolute:
x: 729
y: 267
selected: false
sourcePosition: right
targetPosition: left
type: custom
width: 244
- data:
answer: 'This is Answer Node
{{#1748962354160.output#}}
{{#17489625685610.output#}}'
desc: ''
selected: false
title: 直接回复
type: answer
variables: []
height: 121
id: '1748962443930'
position:
x: 1625.9925571196463
y: 310.910308834967
positionAbsolute:
x: 1625.9925571196463
y: 310.910308834967
selected: false
sourcePosition: right
targetPosition: left
type: custom
width: 244
- data:
code: "\ndef main(arg1: str) -> dict:\n return {\n \"result\": \"\
2a\",\n }\n"
code_language: python3
desc: ''
outputs:
result:
children: null
type: string
selected: false
title: 2a
type: code
variables:
- value_selector:
- sys
- query
variable: arg1
height: 54
id: '17489625222390'
position:
x: 729
y: 396.5
positionAbsolute:
x: 729
y: 396.5
selected: false
sourcePosition: right
targetPosition: left
type: custom
width: 244
- data:
code: "\ndef main(arg1: str) -> dict:\n return {\n \"result\": \"\
2b\",\n }\n"
code_language: python3
desc: ''
outputs:
result:
children: null
type: string
selected: false
title: 2b
type: code
variables:
- value_selector:
- sys
- query
variable: arg1
height: 54
id: '17489625325210'
position:
x: 729
y: 481.5
positionAbsolute:
x: 729
y: 481.5
selected: false
sourcePosition: right
targetPosition: left
type: custom
width: 244
- data:
desc: ''
output_type: string
selected: false
title: b
type: variable-aggregator
variables:
- - '17489624177180'
- result
- - '17489625325210'
- result
height: 131
id: '17489625685610'
position:
x: 1238
y: 396.5
positionAbsolute:
x: 1238
y: 396.5
selected: false
sourcePosition: right
targetPosition: left
type: custom
width: 244
viewport:
x: -189.64043824692612
y: 15.075408994011923
zoom: 0.7453551933994609
✔️ Expected Behavior
For CASE 1 branch of Conditional Branch node, triggers Code Execution node 1A and 1B, and Variable Aggregator node A takes the first None value that is "1a", while Variable Aggregator node B outputs "1b", then the result in the Answer node should be "1a 1b".
So does the CASE 2 branch, the result of Variable Aggregator node A is "2a", node B is "2b", final answer should be "2a2b".
❌ Actual Behavior
When it goes into CASE 1 branch, after the execution of 1A and 1B, Variable Aggregator A and B are both skipped, it just slipped into the final Answer Node with no expected output "1a1b".
But it's weird when it's in CASE 2, everything runs well as my expection, the answer is "2a2b" normally.
If I add an other node like Code Execution node A+B which is used to concat the output from Variable Aggregator nodes A and B, it would throw an unexpected keyword argument error.
Hi @kirakiseki! I'm Dosu and I’m helping the dify team.
Based on your detailed report and the minimal reproduction DSL, here’s what’s happening:
The Variable Aggregator node in Dify is designed to consolidate variables from multiple branches, but it only aggregates the first non-None variable from the selectors you provide. It does not merge results from all branches—only the first available one is used for each aggregator. This is by design and is documented as a limitation: the aggregator is not suitable for collecting all results from multiple workflow branches, and will not combine outputs from parallel or conditional branches into a single output unless each branch is guaranteed to produce a value for the aggregator to pick up. If a branch does not execute (or its output is None), the aggregator may be skipped or produce no output for that path (reference, reference).
In your CASE 1, it appears that the Variable Aggregator nodes are skipped because the expected variables are not present in the variable pool at the time the aggregator runs, likely due to the execution path or how the branches are merged. This can happen if the workflow graph does not guarantee that both code nodes (1A and 1B) always execute and produce outputs before the aggregator runs, or if the aggregator’s selectors do not match the actual outputs produced in that branch.
In contrast, CASE 2 works as expected because both code nodes (2A and 2B) are executed and their outputs are available for aggregation, matching the selectors configured in the aggregator.
If you need to collect and combine results from multiple branches, consider using a Code node or Template node after the branches to explicitly merge the outputs, rather than relying on the Variable Aggregator node (reference). Also, ensure that your workflow graph connects all relevant branches to the aggregator and that the selectors match the outputs produced in each branch.
If you encounter an "unexpected keyword argument" error when adding a Code node to concatenate aggregator outputs, double-check the variable names and ensure that the outputs from the aggregator nodes are correctly referenced in the downstream node’s input configuration.
In summary: the Variable Aggregator node will only pick up the first available variable from its selectors, and may be skipped if none are present. For true merging of results from multiple branches, use a Code or Template node to combine outputs explicitly.
To reply, just mention my name @dosu.
How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other
But why the Case 2 can work normally while the Case 1 doesn't though they have the same structure behind?
Update: Question Classifier node also has this problem.
BTW, if anyone is working on or tracking this issue, feel free to reach me out for further infomation or any kind of help, thanks! :)
Currently, some bugs related to aggregation and graph nodes cannot be addressed yet as we are restructuring the underlying system.
Hi, @kirakiseki. I'm Dosu, and I'm helping the Dify team manage their backlog and am marking this issue as stale.
Issue Summary:
- You reported that Variable Aggregator nodes are skipped in chatflows with conditional branches, leading to missing aggregated outputs.
- It was clarified that Variable Aggregators only pick the first non-None variable and do not merge all branch outputs; explicit merging is recommended.
- You observed a similar issue with the Question Classifier node and questioned the inconsistency.
- A maintainer noted that related aggregation and graph node bugs are pending due to ongoing system restructuring.
- The issue remains unresolved as the underlying system changes are still in progress.
Next Steps:
- Please confirm if this issue is still relevant with the latest version of Dify by commenting here to keep the discussion open.
- Otherwise, I will automatically close this issue in 15 days.
Thank you for your understanding and contribution!
This issue will be completely fixed in #24068.
Hi, @kirakiseki. I'm Dosu, and I'm helping the Dify team manage their backlog and am marking this issue as stale.
Issue Summary:
- You reported that Variable Aggregator nodes in Dify 1.4.1 self-hosted via Docker skip branches unexpectedly, causing incorrect aggregation.
- It was clarified that Variable Aggregators only pick the first non-None variable and do not merge outputs from all branches.
- You also noted a similar issue with the Question Classifier node.
- A maintainer mentioned ongoing system restructuring delaying fixes.
- The issue is set to be fully resolved in PR #24068.
Next Steps:
- Please confirm if this issue is still relevant with the latest version of Dify; if so, you can keep the discussion open by commenting here.
- Otherwise, I will automatically close this issue in 15 days.
Thank you for your understanding and contribution!