delete_endpoint should be idempotent #21624

Closed
opened 2026-02-21 20:13:32 -05:00 by yindo · 1 comment
Owner

Originally created by @fatelei on GitHub (Jan 13, 2026).

Self Checks

  • I have read the Contributing Guide and Language Policy.
  • 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.
  • Please do not modify this template :) and fill in all the required fields.

1. Is this request related to a challenge you're experiencing? Tell me about your story.

delete endpoint is not idempotent

2026-01-14 03:04:04,341 ERROR [app.py:875] 8841449760 Exception on /console/api/workspaces/current/endpoints/delete [POST]
Traceback (most recent call last):
  File "/Users/fatelei/dify/dify/api/.venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/fatelei/dify/dify/api/.venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/fatelei/dify/dify/api/.venv/lib/python3.12/site-packages/flask_restx/api.py", line 404, in wrapper
    resp = resource(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/fatelei/dify/dify/api/.venv/lib/python3.12/site-packages/flask/views.py", line 110, in view
    return current_app.ensure_sync(self.dispatch_request)(**kwargs)  # type: ignore[no-any-return]
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/fatelei/dify/dify/api/.venv/lib/python3.12/site-packages/flask_restx/resource.py", line 41, in dispatch_request
    resp = meth(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/fatelei/dify/dify/api/controllers/console/wraps.py", line 230, in decorated
    return view(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/fatelei/dify/dify/api/libs/login.py", line 80, in decorated_view
    return current_app.ensure_sync(func)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/fatelei/dify/dify/api/controllers/console/wraps.py", line 341, in decorated_function
    return f(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^
  File "/Users/fatelei/dify/dify/api/controllers/console/wraps.py", line 47, in decorated
    return view(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/fatelei/dify/dify/api/controllers/console/workspace/endpoint.py", line 179, in post
    "success": EndpointService.delete_endpoint(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/fatelei/dify/dify/api/services/plugin/endpoint_service.py", line 46, in delete_endpoint
    return PluginEndpointClient().delete_endpoint(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/fatelei/dify/dify/api/core/plugin/impl/endpoint.py", line 74, in delete_endpoint
    return self._request_with_plugin_daemon_response(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/fatelei/dify/dify/api/core/plugin/impl/base.py", line 264, in _request_with_plugin_daemon_response
    self._handle_plugin_daemon_error(error.error_type, error.message)
  File "/Users/fatelei/dify/dify/api/core/plugin/impl/base.py", line 350, in _handle_plugin_daemon_error
    raise PluginDaemonInternalServerError(description=message)
core.plugin.impl.exc.PluginDaemonInternalServerError: req_id: 8841449760 PluginDaemonInternalServerError: failed to remove endpoint: record not found

2. Additional context or comments

No response

3. Can you help us with this feature?

  • I am interested in contributing to this feature.
Originally created by @fatelei on GitHub (Jan 13, 2026). ### 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] 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] Please do not modify this template :) and fill in all the required fields. ### 1. Is this request related to a challenge you're experiencing? Tell me about your story. delete endpoint is not idempotent ``` 2026-01-14 03:04:04,341 ERROR [app.py:875] 8841449760 Exception on /console/api/workspaces/current/endpoints/delete [POST] Traceback (most recent call last): File "/Users/fatelei/dify/dify/api/.venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request rv = self.dispatch_request() ^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/fatelei/dify/dify/api/.venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/fatelei/dify/dify/api/.venv/lib/python3.12/site-packages/flask_restx/api.py", line 404, in wrapper resp = resource(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/fatelei/dify/dify/api/.venv/lib/python3.12/site-packages/flask/views.py", line 110, in view return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/fatelei/dify/dify/api/.venv/lib/python3.12/site-packages/flask_restx/resource.py", line 41, in dispatch_request resp = meth(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "/Users/fatelei/dify/dify/api/controllers/console/wraps.py", line 230, in decorated return view(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "/Users/fatelei/dify/dify/api/libs/login.py", line 80, in decorated_view return current_app.ensure_sync(func)(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/fatelei/dify/dify/api/controllers/console/wraps.py", line 341, in decorated_function return f(*args, **kwargs) ^^^^^^^^^^^^^^^^^^ File "/Users/fatelei/dify/dify/api/controllers/console/wraps.py", line 47, in decorated return view(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "/Users/fatelei/dify/dify/api/controllers/console/workspace/endpoint.py", line 179, in post "success": EndpointService.delete_endpoint( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/fatelei/dify/dify/api/services/plugin/endpoint_service.py", line 46, in delete_endpoint return PluginEndpointClient().delete_endpoint( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/fatelei/dify/dify/api/core/plugin/impl/endpoint.py", line 74, in delete_endpoint return self._request_with_plugin_daemon_response( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/fatelei/dify/dify/api/core/plugin/impl/base.py", line 264, in _request_with_plugin_daemon_response self._handle_plugin_daemon_error(error.error_type, error.message) File "/Users/fatelei/dify/dify/api/core/plugin/impl/base.py", line 350, in _handle_plugin_daemon_error raise PluginDaemonInternalServerError(description=message) core.plugin.impl.exc.PluginDaemonInternalServerError: req_id: 8841449760 PluginDaemonInternalServerError: failed to remove endpoint: record not found ``` ### 2. Additional context or comments _No response_ ### 3. Can you help us with this feature? - [x] I am interested in contributing to this feature.
yindo added the 💪 enhancement label 2026-02-21 20:13:32 -05:00
yindo closed this issue 2026-02-21 20:13:32 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Jan 13, 2026):

Idempotency for DELETE endpoints means that deleting a resource multiple times should have the same effect as deleting it once—if the resource doesn't exist, the operation should still succeed (typically with a 200 or 204 response).

Right now, the delete endpoint raises a PluginDaemonInternalServerError when the record doesn't exist because the error from the plugin daemon is treated as a failure and propagates up the stack see code.

To make this endpoint idempotent, update the error handling in BasePluginClient._handle_plugin_daemon_error (or just after calling it) to treat the "record not found" case as a successful deletion. For example, you could check if the error message or type matches "record not found" and, instead of raising an exception, return a success response. This change would be made in api/core/plugin/impl/base.py and possibly in PluginEndpointClient.delete_endpoint see code.

After updating the logic, add or update tests to verify that deleting both existing and non-existent endpoints returns a success response. Also, review any downstream logic that might depend on the current error behavior to ensure there are no unintended side effects.

If you want to contribute this fix, follow the contributing guide and focus on the files and functions above. Let me know if you want a more detailed code example or have questions about the implementation!

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 (Jan 13, 2026): <!-- Answer --> Idempotency for DELETE endpoints means that deleting a resource multiple times should have the same effect as deleting it once—if the resource doesn't exist, the operation should still succeed (typically with a 200 or 204 response). Right now, the delete endpoint raises a `PluginDaemonInternalServerError` when the record doesn't exist because the error from the plugin daemon is treated as a failure and propagates up the stack [see code](https://github.com/langgenius/dify/blob/d095bd413b1cb7075d7609e4c2b47d1f34619596/api/core/plugin/impl/base.py#L264-L365). To make this endpoint idempotent, update the error handling in `BasePluginClient._handle_plugin_daemon_error` (or just after calling it) to treat the "record not found" case as a successful deletion. For example, you could check if the error message or type matches "record not found" and, instead of raising an exception, return a success response. This change would be made in `api/core/plugin/impl/base.py` and possibly in `PluginEndpointClient.delete_endpoint` [see code](https://github.com/langgenius/dify/blob/d095bd413b1cb7075d7609e4c2b47d1f34619596/api/core/plugin/impl/endpoint.py#L70-L84). After updating the logic, add or update tests to verify that deleting both existing and non-existent endpoints returns a success response. Also, review any downstream logic that might depend on the current error behavior to ensure there are no unintended side effects. If you want to contribute this fix, follow the contributing guide and focus on the files and functions above. Let me know if you want a more detailed code example or have questions about the implementation! <!-- 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/c7d84a98-1a0b-4ce6-8141-5cc826efd389?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/c7d84a98-1a0b-4ce6-8141-5cc826efd389?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/c7d84a98-1a0b-4ce6-8141-5cc826efd389?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/c7d84a98-1a0b-4ce6-8141-5cc826efd389?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/c7d84a98-1a0b-4ce6-8141-5cc826efd389?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/c7d84a98-1a0b-4ce6-8141-5cc826efd389?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/c7d84a98-1a0b-4ce6-8141-5cc826efd389?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=Idempotency%20for%20DELETE%20endpoints%20means%20that%20deleting%20a%20resource%20multiple%20times%20should%20have%20the%20same%20effect%20as%20deleting%20it%20once%E2%80%94if%20the%20resource%20doesn%27t%20exist%2C%20the%20operation%20should%20still%20succeed%20%28typically%20with%20a%20200%20or%20204%20response%29.%0A%0ARight%20now%2C%20the%20delete%20endpoint%20raises%20a%20%60PluginDaemonInternalServerError%60%20when%20the%20record%20doesn%27t%20exist%20because%20the%20error%20from%20the%20plugin%20daemon%20is%20treated%20as%20a%20failure%20and%20propagates%20up%20the%20stack%C2%A0%5Bsee%20code%5D%28https%3A//github.com/langgenius/dify/blob/d095bd413b1cb7075d7609e4c2b47d1f34619596/api/core/plugin/impl/base.py%23L264-L365%29.%0A%0ATo%20make%20this%20endpoint%20idempotent%2C%20update%20the%20error%20handling%20in%20%60BasePluginClient._handle_plugin_daemon_error%60%20%28or%20just%20after%20calling%20it%29%20to%20treat%20the%20%22record%20not%20found%22%20case%20as%20a%20successful%20deletion.%20For%20example%2C%20you%20could%20check%20if%20the%20error%20message%20or%20type%20matches%20%22record%20not%20found%22%20and%2C%20instead%20of%20raising%20an%20exception%2C%20return%20a%20success%20response.%20This%20change%20would%20be%20made%20in%20%60api/core/plugin/impl/base.py%60%20and%20possibly%20in%20%60PluginEndpointClient.delete_endpoint%60%C2%A0%5Bsee%20code%5D%28https%3A//github.com/langgenius/dify/blob/d095bd413b1cb7075d7609e4c2b47d1f34619596/api/core/plugin/impl/endpoint.py%23L70-L84%29.%0A%0AAfter%20updating%20the%20logic%2C%20add%20or%20update%20tests%20to%20verify%20that%20deleting%20both%20existing%20and%20non-existent%20endpoints%20returns%20a%20success%20response.%20Also%2C%20review%20any%20downstream%20logic%20that%20might%20depend%20on%20the%20current%20error%20behavior%20to%20ensure%20there%20are%20no%20unintended%20side%20effects.%0A%0AIf%20you%20want%20to%20contribute%20this%20fix%2C%20follow%20the%20contributing%20guide%20and%20focus%20on%20the%20files%20and%20functions%20above.%20Let%20me%20know%20if%20you%20want%20a%20more%20detailed%20code%20example%20or%20have%20questions%20about%20the%20implementation%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/30953)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#21624