langgenius/dify · error · BadRequest
source workflow must be published
Error message
source workflow must be published
What it means
Raised as BadRequest with the stable message RESTORE_SOURCE_WORKFLOW_MUST_BE_PUBLISHED_MESSAGE ("source workflow must be published", HTTP 400) in RagPipelineDraftWorkflowRestoreApi.post (POST /rag/pipelines/<pipeline_id>/workflows/<workflow_id>/restore). The restore operation copies a previously published workflow back into the draft slot; it can only restore from a workflow that is in the published state. IsDraftWorkflowError from the service is translated to this 400 to keep the response message stable for clients.
Source
Thrown at api/controllers/console/datasets/rag_pipeline/rag_pipeline_workflow.py:712
@setup_required
@login_required
@account_initialization_required
@edit_permission_required
@rbac_permission_required(RBACResourceScope.DATASET, RBACPermission.DATASET_EDIT)
@with_current_user
@get_rag_pipeline
def post(self, current_user: Account, pipeline: Pipeline, workflow_id: str):
rag_pipeline_service = RagPipelineService(db.session())
try:
workflow = rag_pipeline_service.restore_published_workflow_to_draft(
pipeline=pipeline,
workflow_id=workflow_id,
account=current_user,
)
except IsDraftWorkflowError as exc:
# Use a stable, predefined message to keep the 400 response consistent
raise BadRequest(RESTORE_SOURCE_WORKFLOW_MUST_BE_PUBLISHED_MESSAGE) from exc
except WorkflowNotFoundError as exc:
raise NotFound(str(exc)) from exc
return {
"result": "success",
"hash": workflow.unique_hash,
"updated_at": TimestampField().format(workflow.updated_at or workflow.created_at),
}
@console_ns.route("/rag/pipelines/<uuid:pipeline_id>/workflows/<string:workflow_id>")
class RagPipelineByIdApi(Resource):
@console_ns.response(200, "Workflow updated successfully", console_ns.models[WorkflowResponse.__name__])
@console_ns.response(400, "No valid fields to update")
@console_ns.response(403, "Permission denied")
@console_ns.response(404, "Workflow not found")
@setup_required
@login_requiredView on GitHub (pinned to ef8544b173)
Solutions
- Only pass a workflow_id obtained from the published workflows list (GET /rag/pipelines/<id>/workflows), not the draft endpoint.
- If you are already on the draft and want to keep editing, edit it directly instead of restoring.
- In the UI, disable the 'Restore to draft' action for non-published rows.
- Re-fetch the workflow's state before calling restore to confirm it is published.
Example fix
// before POST /rag/pipelines/<id>/workflows/<draft_workflow_id>/restore // -> 400 source workflow must be published // after POST /rag/pipelines/<id>/workflows/<published_workflow_id>/restore
Defensive patterns
Strategy: validation
Validate before calling
async function restoreWorkflow(pipelineId, workflowId) {
const list = await fetch(`/rag/pipelines/${pipelineId}/workflows`).then(r => r.json());
const wf = (list.items ?? []).find(w => w.id === workflowId);
if (!wf || wf.status !== 'published') throw new Error('source workflow must be published');
return fetch(`/rag/pipelines/${pipelineId}/workflows/${workflowId}/restore`, { method: 'POST' });
} Type guard
function isPublishableSource(wf) { return !!wf && wf.status === 'published'; } Try / catch
try { await restoreWorkflow(id, wfId); } catch (e) { if (e.message?.includes('source workflow must be published')) pickPublishedWorkflow(); else throw e; } Prevention
- Only offer restore on rows from the published-workflows list.
- Disable restore on draft rows in the UI.
- Refresh the list before showing the restore action.
When it happens
Trigger: POSTing to the .../restore endpoint with a workflow_id that refers to a draft workflow rather than a published one. The service's restore_published_workflow_to_draft raises IsDraftWorkflowError, which the controller maps to BadRequest.
Common situations: UI lets a user pick a workflow row that is actually the current draft; workflow_id taken from the draft endpoint instead of the published-workflows list; misunderstanding that restore is 'published -> draft', not 'draft -> draft'.
Related errors
- usage_missing_arg
- Invalid filters
- Cannot delete workflow that is currently in use by pipeline
- {str(e)}
- usage_invalid_flag
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/b5d9ef62aaee296c.
Report an issue: GitHub.