{"record":{"id":"d33e5957e4c5bb2a","repo":"langgenius/dify","slug":"source-workflow-must-be-published","errorCode":null,"errorMessage":"source workflow must be published","messagePattern":"source workflow must be published","errorType":"http","errorClass":"BadRequest","httpStatus":400,"severity":"error","filePath":"api/controllers/console/app/workflow.py","lineNumber":1552,"sourceCode":"    @setup_required\n    @login_required\n    @account_initialization_required\n    @get_app_model(mode=[AppMode.ADVANCED_CHAT, AppMode.WORKFLOW])\n    @with_current_user\n    @edit_permission_required\n    @rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_RELEASE_AND_VERSION)\n    def post(self, current_user: Account, app_model: App, workflow_id: str):\n        workflow_service = WorkflowService()\n\n        try:\n            workflow = workflow_service.restore_published_workflow_to_draft(\n                app_model=app_model,\n                workflow_id=workflow_id,\n                account=current_user,\n                session=db.session(),\n            )\n        except IsDraftWorkflowError as exc:\n            raise BadRequest(RESTORE_SOURCE_WORKFLOW_MUST_BE_PUBLISHED_MESSAGE) from exc\n        except WorkflowNotFoundError as exc:\n            raise NotFound(str(exc)) from exc\n        except ValueError as exc:\n            raise BadRequest(str(exc)) from exc\n\n        return {\n            \"result\": \"success\",\n            \"hash\": workflow.unique_hash,\n            \"updated_at\": TimestampField().format(workflow.updated_at or workflow.created_at),\n        }\n\n\n@console_ns.route(\"/apps/<uuid:app_id>/workflows/<string:workflow_id>\")\nclass WorkflowByIdApi(Resource):\n    @console_ns.doc(\"update_workflow_by_id\")\n    @console_ns.doc(description=\"Update workflow by ID\")\n    @console_ns.doc(params={\"app_id\": \"Application ID\", \"workflow_id\": \"Workflow ID\"})\n    @console_ns.expect(console_ns.models[WorkflowUpdatePayload.__name__])","sourceCodeStart":1534,"sourceCodeEnd":1570,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/app/workflow.py#L1534-L1570","documentation":"HTTP 400 BadRequest ('source workflow must be published') raised by DraftWorkflowRestoreApi.post (POST /apps/{app_id}/workflows/{workflow_id}/restore) when WorkflowService.restore_published_workflow_to_draft raises IsDraftWorkflowError. The endpoint restores a PUBLISHED workflow version back into the draft; supplying the workflow_id of a draft (not a published snapshot) is rejected. WorkflowNotFoundError maps to 404 and ValueError maps to 400 respectively in the same try block.","triggerScenarios":"Calling restore with the workflow_id of the app's current draft instead of a published version id; using an id retrieved from the drafts list rather than the published-versions list.","commonSituations":"UI passes the wrong id (draft id) to the restore action; the user expects restore to work on an unpublished draft; confusion between Workflow.id (draft) and published snapshot ids.","solutions":["Use a workflow_id from the published versions list (GET /apps/{app_id}/workflows), not the draft id.","Publish the draft first if you want its content to become restorable.","Verify the workflow_id corresponds to a published row before calling restore."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Only call restore with ids flagged as published.\nconst published = await listPublishedWorkflows(appId);\nif (!published.some(w => w.id === workflowId)) {\n  notifyUser('Select a published version to restore'); return;\n}","typeGuard":"const isPublishedWorkflow = (w): boolean => !!w && w.is_published !== false && !w.is_draft;","tryCatchPattern":"try {\n  return await restoreWorkflow(appId, workflowId);\n} catch (e) {\n  if (e?.status === 400 && /source workflow must be published/i.test(e?.message)) {\n    promptPickPublishedVersion(); return;\n  }\n  throw e;\n}","preventionTips":["Source workflow_id only from the published-versions list, not the drafts list.","Publish the draft first if its content must be restorable later.","Distinguish draft ids from published snapshot ids in the UI."],"tags":["workflow","restore","publish","validation","console-api"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}