langgenius/dify · error

{str(e)}

Error message

{str(e)}

What it means

Flask `abort(400, description=str(e))` (HTTP 400) at api/controllers/console/app/workflow.py:1638 in the workflow DELETE handler. It catches `WorkflowInUseError` (a ValueError subclass from services/errors/workflow_service.py) raised by `WorkflowService.delete_workflow` when the target workflow is still referenced by an app and cannot be removed. The 400 description carries the exception message.

Source

Thrown at api/controllers/console/app/workflow.py:1638

    @edit_permission_required
    @rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_EDIT)
    @console_ns.response(204, "Workflow deleted successfully")
    def delete(self, app_model: App, workflow_id: str):
        """
        Delete workflow
        """
        workflow_service = WorkflowService()
        workflow_ref = WorkflowRefService.create_app_workflow_ref(app_model, workflow_id)

        # Create a session and manage the transaction
        with sessionmaker(db.engine).begin() as session:
            try:
                workflow_service.delete_workflow(
                    session=session,
                    workflow_ref=workflow_ref,
                )
            except WorkflowInUseError as e:
                abort(400, description=str(e))
            except DraftWorkflowDeletionError as e:
                abort(400, description=str(e))
            except ValueError as e:
                raise NotFound(str(e))

        return None, 204


@console_ns.route("/apps/<uuid:app_id>/workflows/draft/nodes/<string:node_id>/last-run")
class DraftWorkflowNodeLastRunApi(Resource):
    @console_ns.doc("get_draft_workflow_node_last_run")
    @console_ns.doc(description="Get last run result for draft workflow node")
    @console_ns.doc(params={"app_id": "Application ID", "node_id": "Node ID"})
    @console_ns.response(
        200,
        "Node last run retrieved successfully",
        console_ns.models[WorkflowRunNodeExecutionResponse.__name__],
    )

View on GitHub (pinned to ef8544b173)

Solutions

  1. Unpublish or detach the workflow from the app before deleting.
  2. Delete or repoint dependent apps/schedules first.
  3. Read the 400 description to see which app references the workflow.

Example fix

// before: deleting an in-use workflow
DELETE /apps/<id>/workflows/<wid>
// after: detach then delete
// 1) switch the app to a different/published workflow
// 2) DELETE /apps/<id>/workflows/<wid>
Defensive patterns

Strategy: validation

Validate before calling

workflow = workflow_service.get_workflow(app_model, workflow_id)
if workflow_service.is_in_use(workflow):
    raise RuntimeError("workflow is in use; detach or unpublish before deleting")

Type guard

def is_safe_to_delete(workflow, service) -> bool:
    return workflow is not None and not service.is_in_use(workflow)

Try / catch

try:
    client.delete(f"/console/api/apps/{app_id}/workflows/{workflow_id}")
except HTTPError as err:
    if err.response.status_code == 400 and "in use" in err.response.text.lower():
        # detach/republish, then retry
        detach_workflow(app_id, workflow_id)
        client.delete(f"/console/api/apps/{app_id}/workflows/{workflow_id}")
    else:
        raise

Prevention

When it happens

Trigger: `DELETE /apps/<app_id>/workflows/<workflow_id>` is called for a workflow that is currently published/active or otherwise referenced by the app, so `delete_workflow` raises `WorkflowInUseError`.

Common situations: Trying to delete the only/active workflow of an app, or deleting a workflow that another app or scheduled job still references.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/85c501dac5f28421. Report an issue: GitHub.