Dify-chatflow-iteration

Question: Does the Dify platform (which version) support the feature of nesting iterative nodes within iterative nodes during the orchestration process

I’ve encountered a similar requirement before—within the same flow, neither iteration nor loops can nest another iteration. At that time, my approach was to extract the inner iteration into a sub-flow (creating a new workflow and publishing it as a tool).

Hope this helps.

Thank you for your response. I also tried your method, but calling the workflow-published tool within an iteration results in an error, and I haven’t yet found a solution.

Dify version: v1.4.1

Error message:

{“event”: “error”, “conversation_id”: “fc5c8beb-7b1b-481f-a3ee-1f0157250820”, “message_id”: “7e74f498-dffb-4f5a-ab52-6440cdff222c”, “created_at”: 1764059934, “code”: “invalid_param”, “status”: 400, “message”: “Run failed: ‘AnonymousUserMixin’ object has no attribute ‘session_id’”}

image

I tried it on the cloud version, and it works.

Two apps:

app:
  description: ''
  icon: 🤖
  icon_background: '#FFEAD5'
  mode: advanced-chat
  name: Outer iteration
  use_icon_as_answer_icon: false
dependencies: []
kind: app
version: 0.5.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_batch_limit: 10
        image_file_size_limit: 10
        single_chunk_attachment_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:
        isInIteration: false
        isInLoop: false
        sourceType: start
        targetType: code
      id: 1767664259503-source-1767664274225-target
      source: '1767664259503'
      sourceHandle: source
      target: '1767664274225'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: code
        targetType: iteration
      id: 1767664274225-source-1767664632458-target
      source: '1767664274225'
      sourceHandle: source
      target: '1767664632458'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: true
        isInLoop: false
        iteration_id: '1767664632458'
        sourceType: iteration-start
        targetType: tool
      id: 1767664632458start-source-1767664645351-target
      source: 1767664632458start
      sourceHandle: source
      target: '1767664645351'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: iteration
        targetType: answer
      id: 1767664632458-source-1767664662774-target
      source: '1767664632458'
      sourceHandle: source
      target: '1767664662774'
      targetHandle: target
      type: custom
      zIndex: 0
    nodes:
    - data:
        selected: false
        title: User Input
        type: start
        variables: []
      height: 73
      id: '1767664259503'
      position:
        x: 0
        y: 49
      positionAbsolute:
        x: 0
        y: 49
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
    - data:
        code: "function main({query}) {\n    return {\n        result: query.split('').filter(it\\\n          => !!it.trim())\n    }\n}\n"
        code_language: javascript
        outputs:
          result:
            children: null
            type: array[string]
        selected: false
        title: Code
        type: code
        variables:
        - value_selector:
          - sys
          - query
          value_type: string
          variable: query
      height: 52
      id: '1767664274225'
      position:
        x: 342
        y: 60
      positionAbsolute:
        x: 342
        y: 60
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
    - data:
        error_handle_mode: terminated
        flatten_output: true
        height: 172
        is_parallel: true
        iterator_input_type: array[string]
        iterator_selector:
        - '1767664274225'
        - result
        output_selector:
        - '1767664645351'
        - output
        output_type: array[string]
        parallel_nums: 10
        selected: false
        start_node_id: 1767664632458start
        title: Iteration
        type: iteration
        width: 620
      height: 172
      id: '1767664632458'
      position:
        x: 684
        y: 0
      positionAbsolute:
        x: 684
        y: 0
      selected: true
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 620
      zIndex: 1
    - data:
        desc: ''
        isInIteration: true
        selected: false
        title: ''
        type: iteration-start
      draggable: false
      height: 48
      id: 1767664632458start
      parentId: '1767664632458'
      position:
        x: 60
        y: 62
      positionAbsolute:
        x: 744
        y: 62
      selectable: false
      sourcePosition: right
      targetPosition: left
      type: custom-iteration-start
      width: 44
      zIndex: 1002
    - data:
        isInIteration: true
        isInLoop: false
        is_team_authorization: true
        iteration_id: '1767664632458'
        paramSchemas:
        - auto_generate: null
          default: ''
          form: llm
          human_description:
            en_US: ''
            ja_JP: ''
            pt_BR: ''
            zh_Hans: ''
          label:
            en_US: text
            ja_JP: text
            pt_BR: text
            zh_Hans: text
          llm_description: ''
          max: null
          min: null
          name: text
          options: []
          placeholder:
            en_US: ''
            ja_JP: ''
            pt_BR: ''
            zh_Hans: ''
          precision: null
          required: true
          scope: null
          template: null
          type: string
        params:
          text: ''
        plugin_id: null
        plugin_unique_identifier: null
        provider_icon:
          background: '#FFEAD5'
          content: 🤖
        provider_id: a8faebfb-0feb-4063-96d4-78de859d17c5
        provider_name: Inner iteration
        provider_type: workflow
        selected: false
        title: Inner iteration
        tool_configurations: {}
        tool_description: ''
        tool_label: Inner iteration
        tool_name: repeat_and_concat_emoji
        tool_node_version: '2'
        tool_parameters:
          text:
            type: mixed
            value: '{{#1767664632458.item#}}'
        type: tool
      height: 52
      id: '1767664645351'
      parentId: '1767664632458'
      position:
        x: 184
        y: 60
      positionAbsolute:
        x: 868
        y: 60
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 1002
    - data:
        answer: '{{#1767664632458.output#}}'
        selected: false
        title: Answer
        type: answer
        variables: []
      height: 103
      id: '1767664662774'
      position:
        x: 1404
        y: 34
      positionAbsolute:
        x: 1404
        y: 34
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
    viewport:
      x: 185.71703578532265
      y: 301.09544880644967
      zoom: 0.5638670037341258
  rag_pipeline_variables: []

And

app:
  description: ''
  icon: 🤖
  icon_background: '#FFEAD5'
  mode: workflow
  name: Inner iteration
  use_icon_as_answer_icon: false
dependencies: []
kind: app
version: 0.5.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_batch_limit: 10
        image_file_size_limit: 10
        single_chunk_attachment_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:
        isInIteration: false
        isInLoop: false
        sourceType: start
        targetType: code
      id: 1767664421409-source-1767664444690-target
      source: '1767664421409'
      sourceHandle: source
      target: '1767664444690'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: code
        targetType: iteration
      id: 1767664444690-source-1767664515327-target
      source: '1767664444690'
      sourceHandle: source
      target: '1767664515327'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: true
        isInLoop: false
        iteration_id: '1767664515327'
        sourceType: iteration-start
        targetType: code
      id: 1767664515327start-source-1767664525741-target
      source: 1767664515327start
      sourceHandle: source
      target: '1767664525741'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: iteration
        targetType: end
      id: 1767664515327-source-1767664551992-target
      source: '1767664515327'
      sourceHandle: source
      target: '1767664551992'
      targetHandle: target
      type: custom
      zIndex: 0
    nodes:
    - data:
        selected: false
        title: User Input
        type: start
        variables:
        - default: ''
          hint: ''
          label: text
          max_length: 48
          options: []
          placeholder: ''
          required: true
          type: paragraph
          variable: text
      height: 109
      id: '1767664421409'
      position:
        x: 0
        y: 146
      positionAbsolute:
        x: 0
        y: 146
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
    - data:
        code: "def main(text: str) -> dict:\n    \"\"\" \n    将输入的字符串重复 3 次,并将其拆分为单个字符的列表。 \n    \n    参数: \n        text (str): 输入的字符串。 \n        \n    返回: \n       \n        dict: 包含结果列表的字典。 \n    \"\"\" \n    # 1. text * 3 对应 JS 的 text.repeat(3) \n    # 2. list(...) 对应 JS 的 .split(\"\"),将字符串转换为字符列表 \n    return {\n       \n        \"result\": list(text * 3)\n    }"
        code_language: python3
        outputs:
          result:
            children: null
            type: array[string]
        selected: false
        title: Code
        type: code
        variables:
        - value_selector:
          - '1767664421409'
          - text
          value_type: string
          variable: text
      height: 52
      id: '1767664444690'
      position:
        x: 342
        y: 175
      positionAbsolute:
        x: 342
        y: 175
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
    - data:
        error_handle_mode: terminated
        flatten_output: true
        height: 402
        is_parallel: false
        iterator_input_type: array[string]
        iterator_selector:
        - '1767664444690'
        - result
        output_selector:
        - '1767664525741'
        - result
        output_type: array[string]
        parallel_nums: 10
        selected: false
        start_node_id: 1767664515327start
        title: Iteration
        type: iteration
        width: 547
      height: 402
      id: '1767664515327'
      position:
        x: 684
        y: 0
      positionAbsolute:
        x: 684
        y: 0
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 547
      zIndex: 1
    - data:
        desc: ''
        isInIteration: true
        selected: false
        title: ''
        type: iteration-start
      draggable: false
      height: 48
      id: 1767664515327start
      parentId: '1767664515327'
      position:
        x: 60
        y: 62
      positionAbsolute:
        x: 744
        y: 62
      selectable: false
      sourcePosition: right
      targetPosition: left
      type: custom-iteration-start
      width: 44
      zIndex: 1002
    - data:
        code: "\ndef main(item: str):\n    return {\n        \"result\": f\"{item} \\U0001F60A\"\n    }\n"
        code_language: python3
        isInIteration: true
        isInLoop: false
        iteration_id: '1767664515327'
        outputs:
          result:
            children: null
            type: string
        selected: false
        title: Code 2
        type: code
        variables:
        - value_selector:
          - '1767664515327'
          - item
          value_type: string
          variable: item
      height: 52
      id: '1767664525741'
      parentId: '1767664515327'
      position:
        x: 184
        y: 60
      positionAbsolute:
        x: 868
        y: 60
      selected: true
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 1002
    - data:
        outputs:
        - value_selector:
          - '1767664515327'
          - output
          value_type: array[string]
          variable: output
        selected: false
        title: Output
        type: end
      height: 88
      id: '1767664551992'
      position:
        x: 1331
        y: 157
      positionAbsolute:
        x: 1331
        y: 157
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
    viewport:
      x: 0
      y: 0
      zoom: 0.7
  rag_pipeline_variables: []

I forgot to mention one thing when replying this morning :joy: , in Dify, previewing works fine as you said, but when calling Dify via API from the frontend, an error occurs.

Are you referring to the method of calling through the Service API? I tried it here and it worked fine.

Judging from your error message, it seems there might be an issue with the User during the call.

It was called through the Service API method, and we also considered it might be a User issue, but haven’t found a solution yet.