Tail Recursion of dify app doesn't work as expected #6251

Closed
opened 2026-02-21 18:14:44 -05:00 by yindo · 2 comments
Owner

Originally created by @wlbksy on GitHub (Oct 22, 2024).

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

0.9.2

Cloud or Self Hosted

Self Hosted (Docker)

Steps to reproduce

The self call only do once if applicable, but the process is not recursive all the way to the bottom case.

for example, I want to repeat input string p for n times. If n is 0 or 1, the result is good. When input n is more than 1, the result is the same as the case of n=1

The following yml omits the dify app auth key

app:
  description: ''
  icon: 🤖
  icon_background: '#FFEAD5'
  mode: workflow
  name: test_self_call
  use_icon_as_answer_icon: false
kind: app
version: 0.1.2
workflow:
  conversation_variables: []
  environment_variables:
  - description: ''
    id: 5025ea98-d849-42b7-93da-ea79fb1515aa
    name: KEY
    value: ''
    value_type: secret
  features:
    file_upload:
      image:
        enabled: false
        number_limits: 3
        transfer_methods:
        - local_file
        - remote_url
    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
        sourceType: if-else
        targetType: end
      id: 1729648898804-true-1729648923379-target
      source: '1729648898804'
      sourceHandle: 'true'
      target: '1729648923379'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: if-else
        targetType: code
      id: 1729648898804-false-1729649078250-target
      source: '1729648898804'
      sourceHandle: 'false'
      target: '1729649078250'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: code
        targetType: http-request
      id: 1729649078250-source-1729648971487-target
      source: '1729649078250'
      sourceHandle: source
      target: '1729648971487'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: http-request
        targetType: code
      id: 1729648971487-source-1729649124083-target
      source: '1729648971487'
      sourceHandle: source
      target: '1729649124083'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: code
        targetType: end
      id: 1729649124083-source-1729649240949-target
      source: '1729649124083'
      sourceHandle: source
      target: '1729649240949'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: start
        targetType: code
      id: 1729648857063-source-1729649515050-target
      source: '1729648857063'
      sourceHandle: source
      target: '1729649515050'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: code
        targetType: if-else
      id: 1729649515050-source-1729648898804-target
      source: '1729649515050'
      sourceHandle: source
      target: '1729648898804'
      targetHandle: target
      type: custom
      zIndex: 0
    nodes:
    - data:
        desc: ''
        selected: false
        title: 开始
        type: start
        variables:
        - label: p
          max_length: 256
          options: []
          required: true
          type: text-input
          variable: p
        - label: n
          max_length: 48
          options: []
          required: true
          type: text-input
          variable: n
      height: 116
      id: '1729648857063'
      position:
        x: 78.47606355800258
        y: 282
      positionAbsolute:
        x: 78.47606355800258
        y: 282
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        cases:
        - case_id: 'true'
          conditions:
          - comparison_operator: 
            id: c3cd8173-54b9-4bb2-8eee-6dcc1f70eec0
            value: '0'
            varType: number
            variable_selector:
            - '1729649515050'
            - n_int
          id: 'true'
          logical_operator: and
        desc: ''
        selected: false
        title: 条件分支
        type: if-else
      height: 126
      id: '1729648898804'
      position:
        x: 684
        y: 282
      positionAbsolute:
        x: 684
        y: 282
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        outputs:
        - value_selector:
          - '1729648857063'
          - p
          variable: p
        selected: false
        title: 结束
        type: end
      height: 90
      id: '1729648923379'
      position:
        x: 988
        y: 282
      positionAbsolute:
        x: 988
        y: 282
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        authorization:
          config:
            api_key: '{{#env.KEY#}}'
            type: bearer
          type: api-key
        body:
          data: "{\n    \"inputs\": {\"p\":\"{{#1729648857063.p#}}\",\n\"n\":\"{{#1729649078250.n_next#}}\"\
            },\n    \"response_mode\": \"blocking\",\n    \"user\": \"abc-123\"\n}"
          type: json
        desc: ''
        headers: Content-Type:application/json
        method: post
        params: ''
        selected: false
        timeout:
          max_connect_timeout: 0
          max_read_timeout: 0
          max_write_timeout: 0
        title: HTTP 请求
        type: http-request
        url: http://127.0.0.1:5001/v1/workflows/run
        variables: []
      height: 110
      id: '1729648971487'
      position:
        x: 1288
        y: 411
      positionAbsolute:
        x: 1288
        y: 411
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        code: "\ndef main(n_int:int) -> dict:\n    return {\n        \"n_next\": str(n_int-1),\n\
          \    }\n"
        code_language: python3
        desc: ''
        outputs:
          n_next:
            children: null
            type: string
        selected: false
        title: 代码执行
        type: code
        variables:
        - value_selector:
          - '1729649515050'
          - n_int
          variable: n_int
      height: 54
      id: '1729649078250'
      position:
        x: 988
        y: 411
      positionAbsolute:
        x: 988
        y: 411
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        code: "import json\n\ndef main(body: str, p: str) -> dict:\n    body_data\
          \ = json.loads(body)\n    data = body_data[\"data\"][\"outputs\"]\n    p1\
          \ = data[\"p\"]\n    return {\n        \"p\": p + ' ' + p1,\n    }\n"
        code_language: python3
        desc: ''
        outputs:
          p:
            children: null
            type: string
        selected: true
        title: 代码执行 2
        type: code
        variables:
        - value_selector:
          - '1729648971487'
          - body
          variable: body
        - value_selector:
          - '1729648857063'
          - p
          variable: p
      height: 54
      id: '1729649124083'
      position:
        x: 1592
        y: 411
      positionAbsolute:
        x: 1592
        y: 411
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        outputs:
        - value_selector:
          - '1729648857063'
          - p
          variable: p
        selected: false
        title: 结束 2
        type: end
      height: 90
      id: '1729649240949'
      position:
        x: 1616.0192961906585
        y: 536.8021405629813
      positionAbsolute:
        x: 1616.0192961906585
        y: 536.8021405629813
      selected: true
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        code: "\ndef main(n: str) -> dict:\n    return {\n        \"n_int\": int(n),\n\
          \    }\n"
        code_language: python3
        desc: ''
        outputs:
          n_int:
            children: null
            type: number
        selected: false
        title: 代码执行 3
        type: code
        variables:
        - value_selector:
          - '1729648857063'
          - n
          variable: n
      height: 54
      id: '1729649515050'
      position:
        x: 384
        y: 282
      positionAbsolute:
        x: 384
        y: 282
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    viewport:
      x: -111.06429371218314
      y: -9.576555709308252
      zoom: 0.8498424618849458

✔️ Expected Behavior

Do the right self recursion

Actual Behavior

The self recursion is not right

Originally created by @wlbksy on GitHub (Oct 22, 2024). ### 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 0.9.2 ### Cloud or Self Hosted Self Hosted (Docker) ### Steps to reproduce The self call only do once if applicable, but the process is not recursive all the way to the bottom case. for example, I want to repeat input string `p` for `n` times. If `n` is 0 or 1, the result is good. When input `n` is more than 1, the result is the same as the case of `n=1` The following yml omits the dify app auth key ```yml app: description: '' icon: 🤖 icon_background: '#FFEAD5' mode: workflow name: test_self_call use_icon_as_answer_icon: false kind: app version: 0.1.2 workflow: conversation_variables: [] environment_variables: - description: '' id: 5025ea98-d849-42b7-93da-ea79fb1515aa name: KEY value: '' value_type: secret features: file_upload: image: enabled: false number_limits: 3 transfer_methods: - local_file - remote_url 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 sourceType: if-else targetType: end id: 1729648898804-true-1729648923379-target source: '1729648898804' sourceHandle: 'true' target: '1729648923379' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false sourceType: if-else targetType: code id: 1729648898804-false-1729649078250-target source: '1729648898804' sourceHandle: 'false' target: '1729649078250' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false sourceType: code targetType: http-request id: 1729649078250-source-1729648971487-target source: '1729649078250' sourceHandle: source target: '1729648971487' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false sourceType: http-request targetType: code id: 1729648971487-source-1729649124083-target source: '1729648971487' sourceHandle: source target: '1729649124083' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false sourceType: code targetType: end id: 1729649124083-source-1729649240949-target source: '1729649124083' sourceHandle: source target: '1729649240949' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false sourceType: start targetType: code id: 1729648857063-source-1729649515050-target source: '1729648857063' sourceHandle: source target: '1729649515050' targetHandle: target type: custom zIndex: 0 - data: isInIteration: false sourceType: code targetType: if-else id: 1729649515050-source-1729648898804-target source: '1729649515050' sourceHandle: source target: '1729648898804' targetHandle: target type: custom zIndex: 0 nodes: - data: desc: '' selected: false title: 开始 type: start variables: - label: p max_length: 256 options: [] required: true type: text-input variable: p - label: n max_length: 48 options: [] required: true type: text-input variable: n height: 116 id: '1729648857063' position: x: 78.47606355800258 y: 282 positionAbsolute: x: 78.47606355800258 y: 282 selected: false sourcePosition: right targetPosition: left type: custom width: 244 - data: cases: - case_id: 'true' conditions: - comparison_operator: ≤ id: c3cd8173-54b9-4bb2-8eee-6dcc1f70eec0 value: '0' varType: number variable_selector: - '1729649515050' - n_int id: 'true' logical_operator: and desc: '' selected: false title: 条件分支 type: if-else height: 126 id: '1729648898804' position: x: 684 y: 282 positionAbsolute: x: 684 y: 282 selected: false sourcePosition: right targetPosition: left type: custom width: 244 - data: desc: '' outputs: - value_selector: - '1729648857063' - p variable: p selected: false title: 结束 type: end height: 90 id: '1729648923379' position: x: 988 y: 282 positionAbsolute: x: 988 y: 282 selected: false sourcePosition: right targetPosition: left type: custom width: 244 - data: authorization: config: api_key: '{{#env.KEY#}}' type: bearer type: api-key body: data: "{\n \"inputs\": {\"p\":\"{{#1729648857063.p#}}\",\n\"n\":\"{{#1729649078250.n_next#}}\"\ },\n \"response_mode\": \"blocking\",\n \"user\": \"abc-123\"\n}" type: json desc: '' headers: Content-Type:application/json method: post params: '' selected: false timeout: max_connect_timeout: 0 max_read_timeout: 0 max_write_timeout: 0 title: HTTP 请求 type: http-request url: http://127.0.0.1:5001/v1/workflows/run variables: [] height: 110 id: '1729648971487' position: x: 1288 y: 411 positionAbsolute: x: 1288 y: 411 selected: false sourcePosition: right targetPosition: left type: custom width: 244 - data: code: "\ndef main(n_int:int) -> dict:\n return {\n \"n_next\": str(n_int-1),\n\ \ }\n" code_language: python3 desc: '' outputs: n_next: children: null type: string selected: false title: 代码执行 type: code variables: - value_selector: - '1729649515050' - n_int variable: n_int height: 54 id: '1729649078250' position: x: 988 y: 411 positionAbsolute: x: 988 y: 411 selected: false sourcePosition: right targetPosition: left type: custom width: 244 - data: code: "import json\n\ndef main(body: str, p: str) -> dict:\n body_data\ \ = json.loads(body)\n data = body_data[\"data\"][\"outputs\"]\n p1\ \ = data[\"p\"]\n return {\n \"p\": p + ' ' + p1,\n }\n" code_language: python3 desc: '' outputs: p: children: null type: string selected: true title: 代码执行 2 type: code variables: - value_selector: - '1729648971487' - body variable: body - value_selector: - '1729648857063' - p variable: p height: 54 id: '1729649124083' position: x: 1592 y: 411 positionAbsolute: x: 1592 y: 411 selected: false sourcePosition: right targetPosition: left type: custom width: 244 - data: desc: '' outputs: - value_selector: - '1729648857063' - p variable: p selected: false title: 结束 2 type: end height: 90 id: '1729649240949' position: x: 1616.0192961906585 y: 536.8021405629813 positionAbsolute: x: 1616.0192961906585 y: 536.8021405629813 selected: true sourcePosition: right targetPosition: left type: custom width: 244 - data: code: "\ndef main(n: str) -> dict:\n return {\n \"n_int\": int(n),\n\ \ }\n" code_language: python3 desc: '' outputs: n_int: children: null type: number selected: false title: 代码执行 3 type: code variables: - value_selector: - '1729648857063' - n variable: n height: 54 id: '1729649515050' position: x: 384 y: 282 positionAbsolute: x: 384 y: 282 selected: false sourcePosition: right targetPosition: left type: custom width: 244 viewport: x: -111.06429371218314 y: -9.576555709308252 zoom: 0.8498424618849458 ``` ### ✔️ Expected Behavior Do the right self recursion ### ❌ Actual Behavior The self recursion is not right
yindo added the 🐞 bug label 2026-02-21 18:14:44 -05:00
yindo closed this issue 2026-02-21 18:14:44 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Oct 22, 2024):

I couldn't find specific information about tail recursion in the Dify app's workflow engine. However, there is a known limitation regarding recursion depth in the Dify app's workflow engine. The _transform_result method checks for recursion depth, and if it exceeds dify_config.CODE_MAX_DEPTH, it raises a ValueError indicating that the object is too deep [1].

Additionally, there is a similar unsolved discussion about issues with session variables and nested iterations, which might be related to your problem. You can find more details in this discussion [2].

If your issue involves recursion depth or session variables, you might want to check these aspects in your workflow configuration.

To continue talking to Dosu, mention @dosu.

@dosubot[bot] commented on GitHub (Oct 22, 2024): <!-- Answer --> I couldn't find specific information about tail recursion in the Dify app's workflow engine. However, there is a known limitation regarding recursion depth in the Dify app's workflow engine. The `_transform_result` method checks for recursion depth, and if it exceeds `dify_config.CODE_MAX_DEPTH`, it raises a `ValueError` indicating that the object is too deep <sup>[[1]](https://github.com/langgenius/dify/blob/main/api/core/workflow/nodes/code/code_node.py)</sup>. Additionally, there is a similar unsolved discussion about issues with session variables and nested iterations, which might be related to your problem. You can find more details in this [discussion](https://github.com/langgenius/dify/discussions/8975) <sup>[[2]](https://github.com/langgenius/dify/discussions/8975)</sup>. If your issue involves recursion depth or session variables, you might want to check these aspects in your workflow configuration. <!-- Dosu Comment Footer --> *To continue talking to [Dosu](https://dosu.dev), mention @dosu.*
Author
Owner

@wlbksy commented on GitHub (Oct 22, 2024):

I should have save the app first. My bad

@wlbksy commented on GitHub (Oct 22, 2024): I should have save the app first. My bad
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#6251