the workflow running has parallel bug when integrate TEMPLATE with CODE #14253

Closed
opened 2026-02-21 19:16:21 -05:00 by yindo · 3 comments
Owner

Originally created by @sontallive on GitHub (May 28, 2025).

Originally assigned to: @Nov1c444 on GitHub.

Self Checks

  • This is only for bug report, if you would like to ask a question, please head to Discussions.
  • I have searched for existing issues search for existing issues, including closed ones.
  • I confirm that I am using English to submit this report (我已阅读并同意 Language Policy).
  • [FOR CHINESE USERS] 请务必使用英文提交 Issue,否则会被关闭。谢谢!:)
  • Please do not modify this template :) and fill in all the required fields.

Dify version

1.4.1

Cloud or Self Hosted

Cloud

Steps to reproduce

If I only have two parallel template node with a code, it works fine.

Image

But when i have two parallel template node with a code, and an extra template parallel with the code, it have bug

Image

The code relies on the template and template2, so it failed, because it run code twice but only have one dependency every run.

Extra info:
the config of the code:

Image

the dsl of the workflow:

app:
  description: ''
  icon: 🤖
  icon_background: '#FFEAD5'
  mode: workflow
  name: test_bug
  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
      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:
        isInIteration: false
        isInLoop: false
        sourceType: start
        targetType: template-transform
      id: 1748420363419-source-1748420383832-target
      source: '1748420363419'
      sourceHandle: source
      target: '1748420383832'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: start
        targetType: template-transform
      id: 1748420363419-source-1748420387199-target
      source: '1748420363419'
      sourceHandle: source
      target: '1748420387199'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: template-transform
        targetType: code
      id: 1748420383832-source-1748420409186-target
      source: '1748420383832'
      sourceHandle: source
      target: '1748420409186'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInLoop: false
        sourceType: template-transform
        targetType: code
      id: 1748420387199-source-1748420409186-target
      source: '1748420387199'
      sourceHandle: source
      target: '1748420409186'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: code
        targetType: end
      id: 1748420409186-source-1748420573290-target
      source: '1748420409186'
      sourceHandle: source
      target: '1748420573290'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: start
        targetType: template-transform
      id: 1748420363419-source-1748421429085-target
      source: '1748420363419'
      sourceHandle: source
      target: '1748421429085'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInLoop: false
        sourceType: template-transform
        targetType: end
      id: 1748421429085-source-1748420573290-target
      source: '1748421429085'
      sourceHandle: source
      target: '1748420573290'
      targetHandle: target
      type: custom
      zIndex: 0
    nodes:
    - data:
        desc: ''
        selected: false
        title: Start
        type: start
        variables: []
      height: 54
      id: '1748420363419'
      position:
        x: 30
        y: 245
      positionAbsolute:
        x: 30
        y: 245
      selected: true
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        selected: false
        template: '123'
        title: Template
        type: template-transform
        variables: []
      height: 54
      id: '1748420383832'
      position:
        x: 334
        y: 245
      positionAbsolute:
        x: 334
        y: 245
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        selected: false
        template: '456'
        title: Template 2
        type: template-transform
        variables: []
      height: 54
      id: '1748420387199'
      position:
        x: 334
        y: 339
      positionAbsolute:
        x: 334
        y: 339
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        code: "import hashlib\nimport random\nimport time\n\ndef main(a: str, b: str)\
          \ -> dict:\n    current_time = str(int(time.time() // 60))\n    combined_seed\
          \ = a + b + current_time\n    seed_value = int(hashlib.md5(combined_seed.encode()).hexdigest()[:8],\
          \ 16)\n    random.seed(seed_value)\n    \n    # Generate random percentage\n\
          \    percentage = random.randint(1, 100)\n    \n    if percentage < 75:\n\
          \        x= a\n    else:\n        x = b\n    \n    return {\n        'result':\
          \ x\n    }\n"
        code_language: python3
        desc: ''
        outputs:
          result:
            children: null
            type: string
        selected: false
        title: Code
        type: code
        variables:
        - value_selector:
          - '1748420383832'
          - output
          variable: a
        - value_selector:
          - '1748420387199'
          - output
          variable: b
      height: 54
      id: '1748420409186'
      position:
        x: 638
        y: 245
      positionAbsolute:
        x: 638
        y: 245
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        outputs:
        - value_selector:
          - '1748420409186'
          - result
          variable: result
        selected: false
        title: End
        type: end
      height: 90
      id: '1748420573290'
      position:
        x: 942
        y: 245
      positionAbsolute:
        x: 942
        y: 245
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        selected: false
        template: '111'
        title: Template 3
        type: template-transform
        variables: []
      height: 54
      id: '1748421429085'
      position:
        x: 638
        y: 396
      positionAbsolute:
        x: 638
        y: 396
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    viewport:
      x: 305.00000000000006
      y: 156.60000000000002
      zoom: 0.7

✔️ Expected Behavior

The code should run once and the two templates run parallel

Actual Behavior

the code run twice with two templates in specific workflow

Originally created by @sontallive on GitHub (May 28, 2025). Originally assigned to: @Nov1c444 on GitHub. ### Self Checks - [x] This is only for bug report, if you would like to ask a question, please head to [Discussions](https://github.com/langgenius/dify/discussions/categories/general). - [x] I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones. - [x] I confirm that I am using English to submit this report (我已阅读并同意 [Language Policy](https://github.com/langgenius/dify/issues/1542)). - [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 Cloud ### Steps to reproduce If I only have two parallel template node with a code, it works fine. <img width="1343" alt="Image" src="https://github.com/user-attachments/assets/f696dad8-1224-4906-9c4c-43969bfeabae" /> But when i have two parallel template node with a code, and an extra template parallel with the code, it have bug <img width="1534" alt="Image" src="https://github.com/user-attachments/assets/a492e730-ae7b-4455-abbc-52f388d4578d" /> The code relies on the template and template2, so it failed, because it run code twice but only have one dependency every run. Extra info: the config of the code: <img width="1153" alt="Image" src="https://github.com/user-attachments/assets/57902030-fc30-42ce-bdbd-80d7196726e9" /> the dsl of the workflow: ```yaml app: description: '' icon: 🤖 icon_background: '#FFEAD5' mode: workflow name: test_bug 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 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: isInIteration: false isInLoop: false sourceType: start targetType: template-transform id: 1748420363419-source-1748420383832-target source: '1748420363419' sourceHandle: source target: '1748420383832' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false isInLoop: false sourceType: start targetType: template-transform id: 1748420363419-source-1748420387199-target source: '1748420363419' sourceHandle: source target: '1748420387199' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false isInLoop: false sourceType: template-transform targetType: code id: 1748420383832-source-1748420409186-target source: '1748420383832' sourceHandle: source target: '1748420409186' targetHandle: target type: custom zIndex: 0 - data: isInLoop: false sourceType: template-transform targetType: code id: 1748420387199-source-1748420409186-target source: '1748420387199' sourceHandle: source target: '1748420409186' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false isInLoop: false sourceType: code targetType: end id: 1748420409186-source-1748420573290-target source: '1748420409186' sourceHandle: source target: '1748420573290' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false isInLoop: false sourceType: start targetType: template-transform id: 1748420363419-source-1748421429085-target source: '1748420363419' sourceHandle: source target: '1748421429085' targetHandle: target type: custom zIndex: 0 - data: isInLoop: false sourceType: template-transform targetType: end id: 1748421429085-source-1748420573290-target source: '1748421429085' sourceHandle: source target: '1748420573290' targetHandle: target type: custom zIndex: 0 nodes: - data: desc: '' selected: false title: Start type: start variables: [] height: 54 id: '1748420363419' position: x: 30 y: 245 positionAbsolute: x: 30 y: 245 selected: true sourcePosition: right targetPosition: left type: custom width: 244 - data: desc: '' selected: false template: '123' title: Template type: template-transform variables: [] height: 54 id: '1748420383832' position: x: 334 y: 245 positionAbsolute: x: 334 y: 245 selected: false sourcePosition: right targetPosition: left type: custom width: 244 - data: desc: '' selected: false template: '456' title: Template 2 type: template-transform variables: [] height: 54 id: '1748420387199' position: x: 334 y: 339 positionAbsolute: x: 334 y: 339 selected: false sourcePosition: right targetPosition: left type: custom width: 244 - data: code: "import hashlib\nimport random\nimport time\n\ndef main(a: str, b: str)\ \ -> dict:\n current_time = str(int(time.time() // 60))\n combined_seed\ \ = a + b + current_time\n seed_value = int(hashlib.md5(combined_seed.encode()).hexdigest()[:8],\ \ 16)\n random.seed(seed_value)\n \n # Generate random percentage\n\ \ percentage = random.randint(1, 100)\n \n if percentage < 75:\n\ \ x= a\n else:\n x = b\n \n return {\n 'result':\ \ x\n }\n" code_language: python3 desc: '' outputs: result: children: null type: string selected: false title: Code type: code variables: - value_selector: - '1748420383832' - output variable: a - value_selector: - '1748420387199' - output variable: b height: 54 id: '1748420409186' position: x: 638 y: 245 positionAbsolute: x: 638 y: 245 selected: false sourcePosition: right targetPosition: left type: custom width: 244 - data: desc: '' outputs: - value_selector: - '1748420409186' - result variable: result selected: false title: End type: end height: 90 id: '1748420573290' position: x: 942 y: 245 positionAbsolute: x: 942 y: 245 selected: false sourcePosition: right targetPosition: left type: custom width: 244 - data: desc: '' selected: false template: '111' title: Template 3 type: template-transform variables: [] height: 54 id: '1748421429085' position: x: 638 y: 396 positionAbsolute: x: 638 y: 396 sourcePosition: right targetPosition: left type: custom width: 244 viewport: x: 305.00000000000006 y: 156.60000000000002 zoom: 0.7 ``` ### ✔️ Expected Behavior The code should run once and the two templates run parallel ### ❌ Actual Behavior the code run twice with two templates in specific workflow
yindo added the 🐞 bug🌊 feat:workflow labels 2026-02-21 19:16:21 -05:00
yindo closed this issue 2026-02-21 19:16:21 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (May 28, 2025):

Hi @sontallive! I'm Dosu and I’m helping the dify team.

The behavior you're seeing is due to a technical limitation in Dify workflows: a node (such as your CODE node) cannot have multiple incoming edges from parallel branches and be expected to run only once. Each node can only have one "parallel ID," so when you connect multiple parallel template nodes to a single code node, Dify treats each incoming edge as a separate execution path, causing the code to run multiple times—once for each incoming edge. This is why your code runs twice instead of once when you add an extra parallel template node.

To work around this, you need to avoid merging multiple parallel branches directly into a single node if you want that node to execute only once. Instead, you should duplicate the code node for each parallel path, or restructure your workflow so that dependencies are explicit and do not converge in a way that violates this limitation. This is a known constraint in Dify's workflow engine and has been discussed in the community: see this explanation and workaround.

If you need the code to run only once after both templates complete, consider introducing an explicit "join" or aggregation node (if supported), or redesign the workflow so that the code node is not directly downstream of multiple parallel branches.

Let me know if you need help with a specific workflow redesign or have further questions about this limitation.

To reply, just mention my name @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Join Discord Share on X

@dosubot[bot] commented on GitHub (May 28, 2025): <!-- Greeting --> Hi @sontallive! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the dify team. <!-- Answer --> The behavior you're seeing is due to a technical limitation in Dify workflows: a node (such as your CODE node) cannot have multiple incoming edges from parallel branches and be expected to run only once. Each node can only have one "parallel ID," so when you connect multiple parallel template nodes to a single code node, Dify treats each incoming edge as a separate execution path, causing the code to run multiple times—once for each incoming edge. This is why your code runs twice instead of once when you add an extra parallel template node. To work around this, you need to avoid merging multiple parallel branches directly into a single node if you want that node to execute only once. Instead, you should duplicate the code node for each parallel path, or restructure your workflow so that dependencies are explicit and do not converge in a way that violates this limitation. This is a known constraint in Dify's workflow engine and has been discussed in the community: [see this explanation and workaround](https://github.com/langgenius/dify/issues/18233). If you need the code to run only once after both templates complete, consider introducing an explicit "join" or aggregation node (if supported), or redesign the workflow so that the code node is not directly downstream of multiple parallel branches. Let me know if you need help with a specific workflow redesign or have further questions about this limitation. <!-- Dosu Comment Footer --> *To reply, just mention my name [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/6addd0f0-10c4-4441-9ca1-3e88698e1ab5?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/6addd0f0-10c4-4441-9ca1-3e88698e1ab5?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/6addd0f0-10c4-4441-9ca1-3e88698e1ab5?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/6addd0f0-10c4-4441-9ca1-3e88698e1ab5?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/6addd0f0-10c4-4441-9ca1-3e88698e1ab5?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/6addd0f0-10c4-4441-9ca1-3e88698e1ab5?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/6addd0f0-10c4-4441-9ca1-3e88698e1ab5?feedback_type=other)</sup>&nbsp;&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/langgenius/dify/issues/20356)
Author
Owner

@sontallive commented on GitHub (May 28, 2025):

If you need the code to run only once after both templates complete, consider introducing an explicit "join" or aggregation node (if supported), or redesign the workflow so that the code node is not directly downstream of multiple parallel branches.

What is a join node in dify, i thought the code reply on two parallelable node should be a join node

@sontallive commented on GitHub (May 28, 2025): > If you need the code to run only once after both templates complete, consider introducing an explicit "join" or aggregation node (if supported), or redesign the workflow so that the code node is not directly downstream of multiple parallel branches. What is a join node in dify, i thought the code reply on two parallelable node should be a join node
Author
Owner

@dosubot[bot] commented on GitHub (May 28, 2025):

Dify does not have a dedicated "join node" like some other workflow engines. In general workflow terminology, a join node synchronizes multiple parallel branches, ensuring that downstream nodes execute only after all incoming branches have completed.

In Dify, however, if you connect multiple parallel branches directly to a single node (like your code node), Dify treats each incoming edge as a separate execution path. This means the node will execute once for each incoming branch, not just once after all branches complete. There is currently no built-in mechanism to aggregate or "join" parallel branches so that a downstream node runs only once after all upstream branches finish. This is a known limitation of Dify's workflow engine and is not addressed by any special node type in the documentation or codebase [source].

To achieve the effect of a join, you would need to restructure your workflow. For example, you could aggregate the outputs of your parallel nodes into a single variable or data structure in a custom node, then trigger your code node from there. Alternatively, you may need to avoid merging multiple parallel branches directly into a single node if you want that node to execute only once.

If you need help designing a workaround for your specific workflow, let me know your requirements and I can suggest a pattern that fits within Dify's current capabilities.

To reply, just mention my name @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Join Discord Share on X

@dosubot[bot] commented on GitHub (May 28, 2025): <!-- Answer --> Dify does not have a dedicated "join node" like some other workflow engines. In general workflow terminology, a join node synchronizes multiple parallel branches, ensuring that downstream nodes execute only after all incoming branches have completed. In Dify, however, if you connect multiple parallel branches directly to a single node (like your code node), Dify treats each incoming edge as a separate execution path. This means the node will execute once for each incoming branch, not just once after all branches complete. There is currently no built-in mechanism to aggregate or "join" parallel branches so that a downstream node runs only once after all upstream branches finish. This is a known limitation of Dify's workflow engine and is not addressed by any special node type in the documentation or codebase [[source]](https://github.com/crazywoola/dify-docs-mintlify/blob/main/en/guides/workflow/orchestrate-node.mdx). To achieve the effect of a join, you would need to restructure your workflow. For example, you could aggregate the outputs of your parallel nodes into a single variable or data structure in a custom node, then trigger your code node from there. Alternatively, you may need to avoid merging multiple parallel branches directly into a single node if you want that node to execute only once. If you need help designing a workaround for your specific workflow, let me know your requirements and I can suggest a pattern that fits within Dify's current capabilities. <!-- Dosu Comment Footer --> *To reply, just mention my name [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/146557b0-08e6-4a43-91d9-31ab2e08e920?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/146557b0-08e6-4a43-91d9-31ab2e08e920?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/146557b0-08e6-4a43-91d9-31ab2e08e920?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/146557b0-08e6-4a43-91d9-31ab2e08e920?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/146557b0-08e6-4a43-91d9-31ab2e08e920?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/146557b0-08e6-4a43-91d9-31ab2e08e920?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/146557b0-08e6-4a43-91d9-31ab2e08e920?feedback_type=other)</sup>&nbsp;&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/langgenius/dify/issues/20356)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#14253