{"record":{"id":"85c501dac5f28421","repo":"langgenius/dify","slug":"str-e-85c501","errorCode":null,"errorMessage":"{str(e)}","messagePattern":"\\{str\\(e\\)\\}","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"api/controllers/console/app/workflow.py","lineNumber":1638,"sourceCode":"    @edit_permission_required\n    @rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_EDIT)\n    @console_ns.response(204, \"Workflow deleted successfully\")\n    def delete(self, app_model: App, workflow_id: str):\n        \"\"\"\n        Delete workflow\n        \"\"\"\n        workflow_service = WorkflowService()\n        workflow_ref = WorkflowRefService.create_app_workflow_ref(app_model, workflow_id)\n\n        # Create a session and manage the transaction\n        with sessionmaker(db.engine).begin() as session:\n            try:\n                workflow_service.delete_workflow(\n                    session=session,\n                    workflow_ref=workflow_ref,\n                )\n            except WorkflowInUseError as e:\n                abort(400, description=str(e))\n            except DraftWorkflowDeletionError as e:\n                abort(400, description=str(e))\n            except ValueError as e:\n                raise NotFound(str(e))\n\n        return None, 204\n\n\n@console_ns.route(\"/apps/<uuid:app_id>/workflows/draft/nodes/<string:node_id>/last-run\")\nclass DraftWorkflowNodeLastRunApi(Resource):\n    @console_ns.doc(\"get_draft_workflow_node_last_run\")\n    @console_ns.doc(description=\"Get last run result for draft workflow node\")\n    @console_ns.doc(params={\"app_id\": \"Application ID\", \"node_id\": \"Node ID\"})\n    @console_ns.response(\n        200,\n        \"Node last run retrieved successfully\",\n        console_ns.models[WorkflowRunNodeExecutionResponse.__name__],\n    )","sourceCodeStart":1620,"sourceCodeEnd":1656,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/app/workflow.py#L1620-L1656","documentation":"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.","triggerScenarios":"`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`.","commonSituations":"Trying to delete the only/active workflow of an app, or deleting a workflow that another app or scheduled job still references.","solutions":["Unpublish or detach the workflow from the app before deleting.","Delete or repoint dependent apps/schedules first.","Read the 400 description to see which app references the workflow."],"exampleFix":"// before: deleting an in-use workflow\nDELETE /apps/<id>/workflows/<wid>\n// after: detach then delete\n// 1) switch the app to a different/published workflow\n// 2) DELETE /apps/<id>/workflows/<wid>","handlingStrategy":"validation","validationCode":"workflow = workflow_service.get_workflow(app_model, workflow_id)\nif workflow_service.is_in_use(workflow):\n    raise RuntimeError(\"workflow is in use; detach or unpublish before deleting\")","typeGuard":"def is_safe_to_delete(workflow, service) -> bool:\n    return workflow is not None and not service.is_in_use(workflow)","tryCatchPattern":"try:\n    client.delete(f\"/console/api/apps/{app_id}/workflows/{workflow_id}\")\nexcept HTTPError as err:\n    if err.response.status_code == 400 and \"in use\" in err.response.text.lower():\n        # detach/republish, then retry\n        detach_workflow(app_id, workflow_id)\n        client.delete(f\"/console/api/apps/{app_id}/workflows/{workflow_id}\")\n    else:\n        raise","preventionTips":["Before DELETE, ensure no app/schedule references the workflow.","Surface the 400 description so the referencing app is identified.","Prefer publishing a new workflow over deleting an active one."],"tags":["workflow","http-400","deletion","dependency","state"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}