Custom tool returns files #21308

Closed
opened 2026-02-21 20:11:54 -05:00 by yindo · 11 comments
Owner

Originally created by @wangzhe06101372-tech on GitHub (Dec 26, 2025).

Self Checks

  • I have read the Contributing Guide and Language Policy.
  • 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, otherwise it will be closed.
  • 【中文用户 & Non English User】请使用英语提交,否则会被关闭 :)
  • Please do not modify this template :) and fill in all the required fields.

Dify version

1.11.1

Cloud or Self Hosted

Cloud, Self Hosted (Docker)

Steps to reproduce

I built a tool locally using Flask that returns files, but when the Dify workflow calls the tool, the result is always a string with "files" being empty.
file_info = { "name": file_name, "size": 512, "type": "image", "extension": file_name.split('.')[-1], "mime_type": mime_type, "transfer_method": "REMOTE_URL", # Correct transfer method "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx" } # 返回文件 return jsonify({ "files": [file_info], }), 200

Image

✔️ Expected Behavior

I expect the returned file to appear in the tool's files field.

Actual Behavior

No response

Originally created by @wangzhe06101372-tech on GitHub (Dec 26, 2025). ### Self Checks - [x] I have read the [Contributing Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) and [Language Policy](https://github.com/langgenius/dify/issues/1542). - [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, otherwise it will be closed. - [x] 【中文用户 & Non English User】请使用英语提交,否则会被关闭 :) - [x] Please do not modify this template :) and fill in all the required fields. ### Dify version 1.11.1 ### Cloud or Self Hosted Cloud, Self Hosted (Docker) ### Steps to reproduce I built a tool locally using Flask that returns files, but when the Dify workflow calls the tool, the result is always a string with "files" being empty. `file_info = { "name": file_name, "size": 512, "type": "image", "extension": file_name.split('.')[-1], "mime_type": mime_type, "transfer_method": "REMOTE_URL", # Correct transfer method "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx" } # 返回文件 return jsonify({ "files": [file_info], }), 200` ![Image](https://github.com/user-attachments/assets/fb5df4bd-f104-40e7-9455-804a766508cd) ### ✔️ Expected Behavior I expect the returned file to appear in the tool's files field. ### ❌ Actual Behavior _No response_
yindo added the 🐞 bug label 2026-02-21 20:11:54 -05:00
yindo closed this issue 2026-02-21 20:11:54 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Dec 26, 2025):

Hi @wangzhe06101372-tech! I'm Dosu and I’m helping the dify team.

Dify doesn't populate the files field from a plain JSON "files" array in your tool's response. Instead, it expects file outputs to be emitted as special file objects with required metadata, or as ToolInvokeMessages of type LINK, IMAGE_LINK, or BINARY_LINK, depending on the file type. If your tool just returns a JSON array with file info, Dify will only show this in the json output, not in files citation.

To make files appear in the files field, your tool's output schema must define the file output using type "file" (for one file) or "arrayFile" (for multiple files), and your response must return file metadata objects with at least these fields:

  • dify_model_identity: "dify__file"
  • transfer_method: "REMOTE_URL"
  • related_id: (unique file id)
  • filename, extension, mime_type
  • url: (valid, accessible HTTP/HTTPS link)

Example:

{
  "attachments": [
    {
      "dify_model_identity": "dify__file",
      "transfer_method": "REMOTE_URL",
      "related_id": "abc123",
      "filename": "result.xlsx",
      "extension": ".xlsx",
      "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      "url": "https://your-server.com/files/result.xlsx"
    }
  ]
}

Your OpenAPI schema for the tool should declare the output as type "arrayFile" under a property like "attachments" citation.

Common pitfalls: missing required fields, inaccessible URLs, or not matching the output schema. Also, make sure your backend can access the file URL, and that transfer_method is set to "REMOTE_URL" citation.

If you still see empty files, check Dify backend logs for validation errors or warnings about file URLs or schema mismatches.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Dec 26, 2025): <!-- Greeting --> Hi @wangzhe06101372-tech! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the dify team. <!-- Answer --> Dify doesn't populate the files field from a plain JSON "files" array in your tool's response. Instead, it expects file outputs to be emitted as special file objects with required metadata, or as ToolInvokeMessages of type LINK, IMAGE_LINK, or BINARY_LINK, depending on the file type. If your tool just returns a JSON array with file info, Dify will only show this in the json output, not in files [citation](https://github.com/langgenius/dify/discussions/30204). To make files appear in the files field, your tool's output schema must define the file output using type "file" (for one file) or "arrayFile" (for multiple files), and your response must return file metadata objects with at least these fields: - dify_model_identity: "dify__file" - transfer_method: "REMOTE_URL" - related_id: (unique file id) - filename, extension, mime_type - url: (valid, accessible HTTP/HTTPS link) Example: ```json { "attachments": [ { "dify_model_identity": "dify__file", "transfer_method": "REMOTE_URL", "related_id": "abc123", "filename": "result.xlsx", "extension": ".xlsx", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "url": "https://your-server.com/files/result.xlsx" } ] } ``` Your OpenAPI schema for the tool should declare the output as type "arrayFile" under a property like "attachments" [citation](https://github.com/langgenius/dify/discussions/30204). Common pitfalls: missing required fields, inaccessible URLs, or not matching the output schema. Also, make sure your backend can access the file URL, and that transfer_method is set to "REMOTE_URL" [citation](https://github.com/langgenius/dify/discussions/24281). If you still see empty files, check Dify backend logs for validation errors or warnings about file URLs or schema mismatches. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/aa9531c9-cad4-4d11-98f0-409a09c9c7bb?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/aa9531c9-cad4-4d11-98f0-409a09c9c7bb?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/aa9531c9-cad4-4d11-98f0-409a09c9c7bb?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/aa9531c9-cad4-4d11-98f0-409a09c9c7bb?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/aa9531c9-cad4-4d11-98f0-409a09c9c7bb?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/aa9531c9-cad4-4d11-98f0-409a09c9c7bb?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/aa9531c9-cad4-4d11-98f0-409a09c9c7bb?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/6088a4f4-073a-43f3-b3d4-4f06fb0c05a0/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=Dify%20doesn%27t%20populate%20the%20files%20field%20from%20a%20plain%20JSON%20%22files%22%20array%20in%20your%20tool%27s%20response.%20Instead%2C%20it%20expects%20file%20outputs%20to%20be%20emitted%20as%20special%20file%20objects%20with%20required%20metadata%2C%20or%20as%20ToolInvokeMessages%20of%20type%20LINK%2C%20IMAGE_LINK%2C%20or%20BINARY_LINK%2C%20depending%20on%20the%20file%20type.%20If%20your%20tool%20just%20returns%20a%20JSON%20array%20with%20file%20info%2C%20Dify%20will%20only%20show%20this%20in%20the%20json%20output%2C%20not%20in%20files%C2%A0%5Bcitation%5D%28https%3A//github.com/langgenius/dify/discussions/30204%29.%0A%0ATo%20make%20files%20appear%20in%20the%20files%20field%2C%20your%20tool%27s%20output%20schema%20must%20define%20the%20file%20output%20using%20type%20%22file%22%20%28for%20one%20file%29%20or%20%22arrayFile%22%20%28for%20multiple%20files%29%2C%20and%20your%20response%20must%20return%20file%20metadata%20objects%20with%20at%20least%20these%20fields%3A%20%0A%0A-%20dify_model_identity%3A%20%22dify__file%22%0A-%20transfer_method%3A%20%22REMOTE_URL%22%0A-%20related_id%3A%20%28unique%20file%20id%29%0A-%20filename%2C%20extension%2C%20mime_type%0A-%20url%3A%20%28valid%2C%20accessible%20HTTP/HTTPS%20link%29%0A%0AExample%3A%0A%60%60%60json%0A%7B%0A%20%20%22attachments%22%3A%20%5B%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22dify_model_identity%22%3A%20%22dify__file%22%2C%0A%20%20%20%20%20%20%22transfer_method%22%3A%20%22REMOTE_URL%22%2C%0A%20%20%20%20%20%20%22related_id%22%3A%20%22abc123%22%2C%0A%20%20%20%20%20%20%22filename%22%3A%20%22result.xlsx%22%2C%0A%20%20%20%20%20%20%22extension%22%3A%20%22.xlsx%22%2C%0A%20%20%20%20%20%20%22mime_type%22%3A%20%22application/vnd.openxmlformats-officedocument.spreadsheetml.sheet%22%2C%0A%20%20%20%20%20%20%22url%22%3A%20%22https%3A//your-server.com/files/result.xlsx%22%0A%20%20%20%20%7D%0A%20%20%5D%0A%7D%0A%60%60%60%0AYour%20OpenAPI%20schema%20for%20the%20tool%20should%20declare%20the%20output%20as%20type%20%22arrayFile%22%20under%20a%20property%20like%20%22attachments%22%C2%A0%5Bcitation%5D%28https%3A//github.com/langgenius/dify/discussions/30204%29.%0A%0ACommon%20pitfalls%3A%20missing%20required%20fields%2C%20inaccessible%20URLs%2C%20or%20not%20matching%20the%20output%20schema.%20Also%2C%20make%20sure%20your%20backend%20can%20access%20the%20file%20URL%2C%20and%20that%20transfer_method%20is%20set%20to%20%22REMOTE_URL%22%C2%A0%5Bcitation%5D%28https%3A//github.com/langgenius/dify/discussions/24281%29.%0A%0AIf%20you%20still%20see%20empty%20files%2C%20check%20Dify%20backend%20logs%20for%20validation%20errors%20or%20warnings%20about%20file%20URLs%20or%20schema%20mismatches.)&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/30214)
Author
Owner

@wangzhe06101372-tech commented on GitHub (Dec 26, 2025):

@dosu. Even using your code to return a result, it still doesn't work.
this is dif tools ouptut
{
"files": [],
"json": [
{
"attachments": [
{
"dify_model_identity": "dify__file",
"extension": ".xlsx",
"filename": "result.xlsx",
"mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"related_id": "abc123",
"transfer_method": "REMOTE_URL",
"url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"
}
]
}
],
"text": "{\n "attachments": [\n {\n "dify_model_identity": "dify__file",\n "extension": ".xlsx",\n "filename": "result.xlsx",\n "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",\n "related_id": "abc123",\n "transfer_method": "REMOTE_URL",\n "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"\n }\n ]\n}\n"
}

@wangzhe06101372-tech commented on GitHub (Dec 26, 2025): [@dosu](https://go.dosu.dev/dosubot). Even using your code to return a result, it still doesn't work. **this is dif tools ouptut** { "files": [], "json": [ { "attachments": [ { "dify_model_identity": "dify__file", "extension": ".xlsx", "filename": "result.xlsx", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "related_id": "abc123", "transfer_method": "REMOTE_URL", "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx" } ] } ], "text": "{\n \"attachments\": [\n {\n \"dify_model_identity\": \"dify__file\",\n \"extension\": \".xlsx\",\n \"filename\": \"result.xlsx\",\n \"mime_type\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \"related_id\": \"abc123\",\n \"transfer_method\": \"REMOTE_URL\",\n \"url\": \"http://10.79.150.163:5000/console/api/v1/static/result.xlsx\"\n }\n ]\n}\n" }
Author
Owner

@dosubot[bot] commented on GitHub (Dec 26, 2025):

This is a known bug in Dify v1.11.1: even if your tool returns the correct file metadata, the files field will always be empty unless the backend emits special ToolInvokeMessages with File objects. The fix for this was merged after your version (PR #27925), and is now included in newer releases. Upgrading Dify is the most robust solution.

If you can't upgrade, you can patch your current version by editing message_transformer.py: change the message type from LINK to BINARY_LINK for file outputs (see discussion and workaround). This will make the files field populate, but may affect compatibility with some plugins or SDKs that only recognize LINK type for downloads.

Also, make sure your tool's output schema uses type "file" or "arrayFile" for file outputs, and that the file URL is accessible from the Dify backend. Just returning file metadata in a JSON array (like attachments) is not enough—Dify only recognizes files if they are emitted as File objects in the correct message type during tool execution.

If you need more details or step-by-step patch instructions, let me know!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Dec 26, 2025): <!-- Answer --> This is a known bug in Dify v1.11.1: even if your tool returns the correct file metadata, the files field will always be empty unless the backend emits special ToolInvokeMessages with File objects. The fix for this was merged after your version ([PR #27925](https://github.com/langgenius/dify/pull/27925)), and is now included in newer releases. Upgrading Dify is the most robust solution. If you can't upgrade, you can patch your current version by editing message_transformer.py: change the message type from LINK to BINARY_LINK for file outputs (see [discussion and workaround](https://github.com/langgenius/dify/issues/26431#issuecomment-3345392568)). This will make the files field populate, but may affect compatibility with some plugins or SDKs that only recognize LINK type for downloads. Also, make sure your tool's output schema uses type "file" or "arrayFile" for file outputs, and that the file URL is accessible from the Dify backend. Just returning file metadata in a JSON array (like attachments) is not enough—Dify only recognizes files if they are emitted as File objects in the correct message type during tool execution. If you need more details or step-by-step patch instructions, let me know! <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/72241190-5ffa-4649-a04a-96bcf258f145?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/72241190-5ffa-4649-a04a-96bcf258f145?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/72241190-5ffa-4649-a04a-96bcf258f145?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/72241190-5ffa-4649-a04a-96bcf258f145?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/72241190-5ffa-4649-a04a-96bcf258f145?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/72241190-5ffa-4649-a04a-96bcf258f145?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/72241190-5ffa-4649-a04a-96bcf258f145?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/6088a4f4-073a-43f3-b3d4-4f06fb0c05a0/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20is%20a%20known%20bug%20in%20Dify%20v1.11.1%3A%20even%20if%20your%20tool%20returns%20the%20correct%20file%20metadata%2C%20the%20files%20field%20will%20always%20be%20empty%20unless%20the%20backend%20emits%20special%20ToolInvokeMessages%20with%20File%20objects.%20The%20fix%20for%20this%20was%20merged%20after%20your%20version%20%28%5BPR%20%2327925%5D%28https%3A//github.com/langgenius/dify/pull/27925%29%29%2C%20and%20is%20now%20included%20in%20newer%20releases.%20Upgrading%20Dify%20is%20the%20most%20robust%20solution.%0A%0AIf%20you%20can%27t%20upgrade%2C%20you%20can%20patch%20your%20current%20version%20by%20editing%20message_transformer.py%3A%20change%20the%20message%20type%20from%20LINK%20to%20BINARY_LINK%20for%20file%20outputs%20%28see%20%5Bdiscussion%20and%20workaround%5D%28https%3A//github.com/langgenius/dify/issues/26431%23issuecomment-3345392568%29%29.%20This%20will%20make%20the%20files%20field%20populate%2C%20but%20may%20affect%20compatibility%20with%20some%20plugins%20or%20SDKs%20that%20only%20recognize%20LINK%20type%20for%20downloads.%0A%0AAlso%2C%20make%20sure%20your%20tool%27s%20output%20schema%20uses%20type%20%22file%22%20or%20%22arrayFile%22%20for%20file%20outputs%2C%20and%20that%20the%20file%20URL%20is%20accessible%20from%20the%20Dify%20backend.%20Just%20returning%20file%20metadata%20in%20a%20JSON%20array%20%28like%20attachments%29%20is%20not%20enough%E2%80%94Dify%20only%20recognizes%20files%20if%20they%20are%20emitted%20as%20File%20objects%20in%20the%20correct%20message%20type%20during%20tool%20execution.%20%0A%0AIf%20you%20need%20more%20details%20or%20step-by-step%20patch%20instructions%2C%20let%20me%20know%21)&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/30214)
Author
Owner

@wangzhe06101372-tech commented on GitHub (Dec 26, 2025):

@dosu. so this bug is solved in master branch? how can i update my vison

@wangzhe06101372-tech commented on GitHub (Dec 26, 2025): [@dosu](https://go.dosu.dev/dosubot). so this bug is solved in master branch? how can i update my vison
Author
Owner

@dosubot[bot] commented on GitHub (Dec 26, 2025):

Yes, this bug is fixed in the master branch and in all versions after 1.11.1 (source). To update your Dify deployment (Docker/self-hosted), follow these steps:

  1. Back up your database, Docker volumes, .env, and docker-compose.yaml.
  2. Stop all running containers: docker compose down
  3. Pull the latest code and update your docker-compose.yaml and .env files to match the new version (compare with the latest .env.example and docker-compose.yaml).
  4. Pull the latest images: docker compose pull
  5. Start the new containers: docker compose up -d
  6. Run database and plugin migrations inside the API container:
    docker compose exec api uv run flask db upgrade
    docker compose exec api uv run flask extract-plugins --workers=20
    docker compose exec api uv run flask install-plugins --workers=2
    docker compose exec api uv run flask migrate-data-for-plugin
    
  7. Adjust permissions if needed (e.g., sudo chown -R 1001:1001 ./volumes/app/storage)
  8. Restart all services: docker compose down && docker compose up -d
  9. Log in and verify everything works as expected (upgrade guide).

There is no auto-upgrade script; the process is manual. Make sure to update both your .env and docker-compose.yaml to the latest version and migrate any custom settings. Your data volumes can be reused as long as they are correctly mounted and preserved. No breaking changes prevent volume-based migration from 1.7.2 to the latest version if you follow the migration steps and back up your data (migration advice).

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Dec 26, 2025): <!-- Answer --> Yes, this bug is fixed in the master branch and in all versions after 1.11.1 ([source](https://github.com/langgenius/dify/issues/30057#issuecomment-3688524092)). To update your Dify deployment (Docker/self-hosted), follow these steps: 1. Back up your database, Docker volumes, .env, and docker-compose.yaml. 2. Stop all running containers: `docker compose down` 3. Pull the latest code and update your docker-compose.yaml and .env files to match the new version (compare with the latest `.env.example` and `docker-compose.yaml`). 4. Pull the latest images: `docker compose pull` 5. Start the new containers: `docker compose up -d` 6. Run database and plugin migrations inside the API container: ``` docker compose exec api uv run flask db upgrade docker compose exec api uv run flask extract-plugins --workers=20 docker compose exec api uv run flask install-plugins --workers=2 docker compose exec api uv run flask migrate-data-for-plugin ``` 7. Adjust permissions if needed (e.g., `sudo chown -R 1001:1001 ./volumes/app/storage`) 8. Restart all services: `docker compose down && docker compose up -d` 9. Log in and verify everything works as expected ([upgrade guide](https://github.com/langgenius/dify/discussions/29865#discussioncomment-15286877)). There is no auto-upgrade script; the process is manual. Make sure to update both your .env and docker-compose.yaml to the latest version and migrate any custom settings. Your data volumes can be reused as long as they are correctly mounted and preserved. No breaking changes prevent volume-based migration from 1.7.2 to the latest version if you follow the migration steps and back up your data ([migration advice](https://github.com/langgenius/dify/issues/29081#issuecomment-3605976888)). <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/c629fdf3-e0d3-4ca7-8f8e-af7af122becc?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/c629fdf3-e0d3-4ca7-8f8e-af7af122becc?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/c629fdf3-e0d3-4ca7-8f8e-af7af122becc?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/c629fdf3-e0d3-4ca7-8f8e-af7af122becc?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/c629fdf3-e0d3-4ca7-8f8e-af7af122becc?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/c629fdf3-e0d3-4ca7-8f8e-af7af122becc?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/c629fdf3-e0d3-4ca7-8f8e-af7af122becc?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/6088a4f4-073a-43f3-b3d4-4f06fb0c05a0/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=Yes%2C%20this%20bug%20is%20fixed%20in%20the%20master%20branch%20and%20in%20all%20versions%20after%201.11.1%C2%A0%28%5Bsource%5D%28https%3A//github.com/langgenius/dify/issues/30057%23issuecomment-3688524092%29%29.%20To%20update%20your%20Dify%20deployment%20%28Docker/self-hosted%29%2C%20follow%20these%20steps%3A%0A%0A1.%20Back%20up%20your%20database%2C%20Docker%20volumes%2C%20.env%2C%20and%20docker-compose.yaml.%0A2.%20Stop%20all%20running%20containers%3A%20%60docker%20compose%20down%60%0A3.%20Pull%20the%20latest%20code%20and%20update%20your%20docker-compose.yaml%20and%20.env%20files%20to%20match%20the%20new%20version%20%28compare%20with%20the%20latest%20%60.env.example%60%20and%20%60docker-compose.yaml%60%29.%0A4.%20Pull%20the%20latest%20images%3A%20%60docker%20compose%20pull%60%0A5.%20Start%20the%20new%20containers%3A%20%60docker%20compose%20up%20-d%60%0A6.%20Run%20database%20and%20plugin%20migrations%20inside%20the%20API%20container%3A%0A%20%20%20%60%60%60%0A%20%20%20docker%20compose%20exec%20api%20uv%20run%20flask%20db%20upgrade%0A%20%20%20docker%20compose%20exec%20api%20uv%20run%20flask%20extract-plugins%20--workers%3D20%0A%20%20%20docker%20compose%20exec%20api%20uv%20run%20flask%20install-plugins%20--workers%3D2%0A%20%20%20docker%20compose%20exec%20api%20uv%20run%20flask%20migrate-data-for-plugin%0A%20%20%20%60%60%60%0A7.%20Adjust%20permissions%20if%20needed%20%28e.g.%2C%20%60sudo%20chown%20-R%201001%3A1001%20./volumes/app/storage%60%29%0A8.%20Restart%20all%20services%3A%20%60docker%20compose%20down%20%26%26%20docker%20compose%20up%20-d%60%0A9.%20Log%20in%20and%20verify%20everything%20works%20as%20expected%C2%A0%28%5Bupgrade%20guide%5D%28https%3A//github.com/langgenius/dify/discussions/29865%23discussioncomment-15286877%29%29.%0A%0AThere%20is%20no%20auto-upgrade%20script%3B%20the%20process%20is%20manual.%20Make%20sure%20to%20update%20both%20your%20.env%20and%20docker-compose.yaml%20to%20the%20latest%20version%20and%20migrate%20any%20custom%20settings.%20Your%20data%20volumes%20can%20be%20reused%20as%20long%20as%20they%20are%20correctly%20mounted%20and%20preserved.%20No%20breaking%20changes%20prevent%20volume-based%20migration%20from%201.7.2%20to%20the%20latest%20version%20if%20you%20follow%20the%20migration%20steps%20and%20back%20up%20your%20data%C2%A0%28%5Bmigration%20advice%5D%28https%3A//github.com/langgenius/dify/issues/29081%23issuecomment-3605976888%29%29.)&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/30214)
Author
Owner

@wangzhe06101372-tech commented on GitHub (Dec 26, 2025):

@dosu. so the version 1.11.2 fix the bug?
but I still cant read files

tools return

return {
"attachments": [
{
"dify_model_identity": "dify__file",
"transfer_method": "REMOTE_URL",
"related_id": "abc123",
"filename": "result.xlsx",
"extension": ".xlsx",
"mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"
}
]
}, 200

the dify get message is
{
"files": [],
"json": [
{
"attachments": [
{
"dify_model_identity": "dify__file",
"extension": ".xlsx",
"filename": "result.xlsx",
"mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"related_id": "abc123",
"transfer_method": "REMOTE_URL",
"url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"
}
]
}
],
"text": "{\n "attachments": [\n {\n "dify_model_identity": "dify__file",\n "extension": ".xlsx",\n "filename": "result.xlsx",\n "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",\n "related_id": "abc123",\n "transfer_method": "REMOTE_URL",\n "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"\n }\n ]\n}\n"
}

the log still is show

[on_tool_execution]

Tool: calculateLoadSimulation

Outputs: {"type":"json","message":{"json_object":{"attachments":[{"dify_model_identity":"dify__file","extension":".xlsx","filename":"result.xlsx","mime_type":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","related_id":"abc123","transfer_method":"REMOTE_URL","url":"http://10.79.150.163:5000/console/api/v1/static/result.xlsx"}]},"suppress_output":false},"meta":null}

[on_tool_execution]

Tool: calculateLoadSimulation

Outputs: {"type":"text","message":{"text":"{\n "attachments": [\n {\n "dify_model_identity": "dify__file",\n "extension": ".xlsx",\n "filename": "result.xlsx",\n "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",\n "related_id": "abc123",\n "transfer_method": "REMOTE_URL",\n "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"\n }\n ]\n}\n"},"meta":null}

how can i solve the problem

@wangzhe06101372-tech commented on GitHub (Dec 26, 2025): [@dosu](https://go.dosu.dev/dosubot). so the version 1.11.2 fix the bug? but I still cant read files tools return return { "attachments": [ { "dify_model_identity": "dify__file", "transfer_method": "REMOTE_URL", "related_id": "abc123", "filename": "result.xlsx", "extension": ".xlsx", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx" } ] }, 200 the dify get message is { "files": [], "json": [ { "attachments": [ { "dify_model_identity": "dify__file", "extension": ".xlsx", "filename": "result.xlsx", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "related_id": "abc123", "transfer_method": "REMOTE_URL", "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx" } ] } ], "text": "{\n \"attachments\": [\n {\n \"dify_model_identity\": \"dify__file\",\n \"extension\": \".xlsx\",\n \"filename\": \"result.xlsx\",\n \"mime_type\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \"related_id\": \"abc123\",\n \"transfer_method\": \"REMOTE_URL\",\n \"url\": \"http://10.79.150.163:5000/console/api/v1/static/result.xlsx\"\n }\n ]\n}\n" } the log still is show [on_tool_execution] Tool: calculateLoadSimulation Outputs: {"type":"json","message":{"json_object":{"attachments":[{"dify_model_identity":"dify__file","extension":".xlsx","filename":"result.xlsx","mime_type":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","related_id":"abc123","transfer_method":"REMOTE_URL","url":"http://10.79.150.163:5000/console/api/v1/static/result.xlsx"}]},"suppress_output":false},"meta":null} [on_tool_execution] Tool: calculateLoadSimulation Outputs: {"type":"text","message":{"text":"{\n \"attachments\": [\n {\n \"dify_model_identity\": \"dify__file\",\n \"extension\": \".xlsx\",\n \"filename\": \"result.xlsx\",\n \"mime_type\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \"related_id\": \"abc123\",\n \"transfer_method\": \"REMOTE_URL\",\n \"url\": \"http://10.79.150.163:5000/console/api/v1/static/result.xlsx\"\n }\n ]\n}\n"},"meta":null} **how can i solve the problem**
Author
Owner

@fatelei commented on GitHub (Dec 27, 2025):

@dosu. so the version 1.11.2 fix the bug? but I still cant read files

tools return

return { "attachments": [ { "dify_model_identity": "dify__file", "transfer_method": "REMOTE_URL", "related_id": "abc123", "filename": "result.xlsx", "extension": ".xlsx", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx" } ] }, 200

the dify get message is { "files": [], "json": [ { "attachments": [ { "dify_model_identity": "dify__file", "extension": ".xlsx", "filename": "result.xlsx", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "related_id": "abc123", "transfer_method": "REMOTE_URL", "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx" } ] } ], "text": "{\n "attachments": [\n {\n "dify_model_identity": "dify__file",\n "extension": ".xlsx",\n "filename": "result.xlsx",\n "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",\n "related_id": "abc123",\n "transfer_method": "REMOTE_URL",\n "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"\n }\n ]\n}\n" }

the log still is show

[on_tool_execution]

Tool: calculateLoadSimulation

Outputs: {"type":"json","message":{"json_object":{"attachments":[{"dify_model_identity":"dify__file","extension":".xlsx","filename":"result.xlsx","mime_type":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","related_id":"abc123","transfer_method":"REMOTE_URL","url":"http://10.79.150.163:5000/console/api/v1/static/result.xlsx"}]},"suppress_output":false},"meta":null}

[on_tool_execution]

Tool: calculateLoadSimulation

Outputs: {"type":"text","message":{"text":"{\n "attachments": [\n {\n "dify_model_identity": "dify__file",\n "extension": ".xlsx",\n "filename": "result.xlsx",\n "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",\n "related_id": "abc123",\n "transfer_method": "REMOTE_URL",\n "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"\n }\n ]\n}\n"},"meta":null}

how can i solve the problem

because in custom_tool/tool.py

 # assemble invoke message based on response type
        if parsed_response.is_json:
            if isinstance(parsed_response.content, dict):
                yield self.create_json_message(parsed_response.content)

            # The yield below must be preserved to keep backward compatibility.
            #
            # ref: https://github.com/langgenius/dify/pull/23456#issuecomment-3182413088
            yield self.create_text_message(response.text)
        else:
            # Convert to string if needed and create text message
            text_response = (
                parsed_response.content if isinstance(parsed_response.content, str) else str(parsed_response.content)
            )
            yield self.create_text_message(text_response)

it create json message, not file message, so you can not get file

@fatelei commented on GitHub (Dec 27, 2025): > [@dosu](https://go.dosu.dev/dosubot). so the version 1.11.2 fix the bug? but I still cant read files > > tools return > > return { "attachments": [ { "dify_model_identity": "dify__file", "transfer_method": "REMOTE_URL", "related_id": "abc123", "filename": "result.xlsx", "extension": ".xlsx", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx" } ] }, 200 > > the dify get message is { "files": [], "json": [ { "attachments": [ { "dify_model_identity": "dify__file", "extension": ".xlsx", "filename": "result.xlsx", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "related_id": "abc123", "transfer_method": "REMOTE_URL", "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx" } ] } ], "text": "{\n "attachments": [\n {\n "dify_model_identity": "dify__file",\n "extension": ".xlsx",\n "filename": "result.xlsx",\n "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",\n "related_id": "abc123",\n "transfer_method": "REMOTE_URL",\n "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"\n }\n ]\n}\n" } > > the log still is show > > [on_tool_execution] > > Tool: calculateLoadSimulation > > Outputs: {"type":"json","message":{"json_object":{"attachments":[{"dify_model_identity":"dify__file","extension":".xlsx","filename":"result.xlsx","mime_type":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","related_id":"abc123","transfer_method":"REMOTE_URL","url":"http://10.79.150.163:5000/console/api/v1/static/result.xlsx"}]},"suppress_output":false},"meta":null} > > [on_tool_execution] > > Tool: calculateLoadSimulation > > Outputs: {"type":"text","message":{"text":"{\n "attachments": [\n {\n "dify_model_identity": "dify__file",\n "extension": ".xlsx",\n "filename": "result.xlsx",\n "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",\n "related_id": "abc123",\n "transfer_method": "REMOTE_URL",\n "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"\n }\n ]\n}\n"},"meta":null} > > **how can i solve the problem** because in custom_tool/tool.py ```python # assemble invoke message based on response type if parsed_response.is_json: if isinstance(parsed_response.content, dict): yield self.create_json_message(parsed_response.content) # The yield below must be preserved to keep backward compatibility. # # ref: https://github.com/langgenius/dify/pull/23456#issuecomment-3182413088 yield self.create_text_message(response.text) else: # Convert to string if needed and create text message text_response = ( parsed_response.content if isinstance(parsed_response.content, str) else str(parsed_response.content) ) yield self.create_text_message(text_response) ``` it create json message, not file message, so you can not get file
Author
Owner

@fatelei commented on GitHub (Dec 27, 2025):

@dosu. so the version 1.11.2 fix the bug? but I still cant read files

tools return

return { "attachments": [ { "dify_model_identity": "dify__file", "transfer_method": "REMOTE_URL", "related_id": "abc123", "filename": "result.xlsx", "extension": ".xlsx", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx" } ] }, 200

the dify get message is { "files": [], "json": [ { "attachments": [ { "dify_model_identity": "dify__file", "extension": ".xlsx", "filename": "result.xlsx", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "related_id": "abc123", "transfer_method": "REMOTE_URL", "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx" } ] } ], "text": "{\n "attachments": [\n {\n "dify_model_identity": "dify__file",\n "extension": ".xlsx",\n "filename": "result.xlsx",\n "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",\n "related_id": "abc123",\n "transfer_method": "REMOTE_URL",\n "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"\n }\n ]\n}\n" }

the log still is show

[on_tool_execution]

Tool: calculateLoadSimulation

Outputs: {"type":"json","message":{"json_object":{"attachments":[{"dify_model_identity":"dify__file","extension":".xlsx","filename":"result.xlsx","mime_type":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","related_id":"abc123","transfer_method":"REMOTE_URL","url":"http://10.79.150.163:5000/console/api/v1/static/result.xlsx"}]},"suppress_output":false},"meta":null}

[on_tool_execution]

Tool: calculateLoadSimulation

Outputs: {"type":"text","message":{"text":"{\n "attachments": [\n {\n "dify_model_identity": "dify__file",\n "extension": ".xlsx",\n "filename": "result.xlsx",\n "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",\n "related_id": "abc123",\n "transfer_method": "REMOTE_URL",\n "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"\n }\n ]\n}\n"},"meta":null}

how can i solve the problem

if you want to get file, you can modify custom_tool/tool.py add method below

    def _extract_and_yield_files(self, content: dict[str, Any], tenant_id: str) -> None:
        """
        Extract files from JSON content and yield file messages.

        This method recursively searches for 'files' fields in the JSON response
        and creates File objects for each valid file entry.

        Expected file structure:
        {
            "files": [
                {
                    "name": "filename.txt",
                    "url": "http://...",
                    "extension": "txt",
                    "mime_type": "text/plain",
                    "size": 1024,
                    "transfer_method": "REMOTE_URL"
                }
            ]
        }
        """
        if not isinstance(content, dict):
            return

        # Check if this level has a 'files' key
        if "files" in content:
            files_data = content["files"]
            if isinstance(files_data, list):
                for file_info in files_data:
                    if isinstance(file_info, dict) and self._is_valid_file_info(file_info):
                        try:
                            file_obj = File(
                                tenant_id=tenant_id,
                                transfer_method=FileTransferMethod(file_info.get("transfer_method", "remote_url")),
                                remote_url=file_info.get("url"),
                                filename=file_info.get("name"),
                                extension=file_info.get("extension"),
                                mime_type=file_info.get("mime_type"),
                                size=file_info.get("size", 0),
                                type=file_info.get("type", FileType.CUSTOM),
                            )
                            yield self.create_file_message(file_obj)
                        except Exception:
                            # Skip invalid file entries
                            pass

        # Recursively search nested dictionaries
        for value in content.values():
            if isinstance(value, dict):
                yield from self._extract_and_yield_files(value, tenant_id)
            elif isinstance(value, list):
                for item in value:
                    if isinstance(item, dict):
                        yield from self._extract_and_yield_files(item, tenant_id)

    def _is_valid_file_info(self, file_info: dict[str, Any]) -> bool:
        """
        Check if the file_info dictionary contains required fields.
        """
        return bool(file_info.get("url") and file_info.get("name"))

and modify the line 402, add method call yield from self._extract_and_yield_files(parsed_response.content, user_id)

@fatelei commented on GitHub (Dec 27, 2025): > [@dosu](https://go.dosu.dev/dosubot). so the version 1.11.2 fix the bug? but I still cant read files > > tools return > > return { "attachments": [ { "dify_model_identity": "dify__file", "transfer_method": "REMOTE_URL", "related_id": "abc123", "filename": "result.xlsx", "extension": ".xlsx", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx" } ] }, 200 > > the dify get message is { "files": [], "json": [ { "attachments": [ { "dify_model_identity": "dify__file", "extension": ".xlsx", "filename": "result.xlsx", "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "related_id": "abc123", "transfer_method": "REMOTE_URL", "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx" } ] } ], "text": "{\n "attachments": [\n {\n "dify_model_identity": "dify__file",\n "extension": ".xlsx",\n "filename": "result.xlsx",\n "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",\n "related_id": "abc123",\n "transfer_method": "REMOTE_URL",\n "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"\n }\n ]\n}\n" } > > the log still is show > > [on_tool_execution] > > Tool: calculateLoadSimulation > > Outputs: {"type":"json","message":{"json_object":{"attachments":[{"dify_model_identity":"dify__file","extension":".xlsx","filename":"result.xlsx","mime_type":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","related_id":"abc123","transfer_method":"REMOTE_URL","url":"http://10.79.150.163:5000/console/api/v1/static/result.xlsx"}]},"suppress_output":false},"meta":null} > > [on_tool_execution] > > Tool: calculateLoadSimulation > > Outputs: {"type":"text","message":{"text":"{\n "attachments": [\n {\n "dify_model_identity": "dify__file",\n "extension": ".xlsx",\n "filename": "result.xlsx",\n "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",\n "related_id": "abc123",\n "transfer_method": "REMOTE_URL",\n "url": "http://10.79.150.163:5000/console/api/v1/static/result.xlsx"\n }\n ]\n}\n"},"meta":null} > > **how can i solve the problem** if you want to get file, you can modify custom_tool/tool.py add method below ```python def _extract_and_yield_files(self, content: dict[str, Any], tenant_id: str) -> None: """ Extract files from JSON content and yield file messages. This method recursively searches for 'files' fields in the JSON response and creates File objects for each valid file entry. Expected file structure: { "files": [ { "name": "filename.txt", "url": "http://...", "extension": "txt", "mime_type": "text/plain", "size": 1024, "transfer_method": "REMOTE_URL" } ] } """ if not isinstance(content, dict): return # Check if this level has a 'files' key if "files" in content: files_data = content["files"] if isinstance(files_data, list): for file_info in files_data: if isinstance(file_info, dict) and self._is_valid_file_info(file_info): try: file_obj = File( tenant_id=tenant_id, transfer_method=FileTransferMethod(file_info.get("transfer_method", "remote_url")), remote_url=file_info.get("url"), filename=file_info.get("name"), extension=file_info.get("extension"), mime_type=file_info.get("mime_type"), size=file_info.get("size", 0), type=file_info.get("type", FileType.CUSTOM), ) yield self.create_file_message(file_obj) except Exception: # Skip invalid file entries pass # Recursively search nested dictionaries for value in content.values(): if isinstance(value, dict): yield from self._extract_and_yield_files(value, tenant_id) elif isinstance(value, list): for item in value: if isinstance(item, dict): yield from self._extract_and_yield_files(item, tenant_id) def _is_valid_file_info(self, file_info: dict[str, Any]) -> bool: """ Check if the file_info dictionary contains required fields. """ return bool(file_info.get("url") and file_info.get("name")) ``` and modify the line 402, add method call `yield from self._extract_and_yield_files(parsed_response.content, user_id)`
Author
Owner

@fatelei commented on GitHub (Dec 27, 2025):

currently dify is not support get file obj from custom tool call

@fatelei commented on GitHub (Dec 27, 2025): currently dify is not support get file obj from custom tool call
Author
Owner

@fatelei commented on GitHub (Dec 27, 2025):

i think this is not a bug

@fatelei commented on GitHub (Dec 27, 2025): i think this is not a bug
Author
Owner

@wangzhe06101372-tech commented on GitHub (Dec 29, 2025):

I really appreciate it.

@wangzhe06101372-tech commented on GitHub (Dec 29, 2025): I really appreciate it.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#21308