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_required

View on GitHub (pinned to ef8544b173)

Solutions

  1. Only pass a workflow_id obtained from the published workflows list (GET /rag/pipelines/<id>/workflows), not the draft endpoint.
  2. If you are already on the draft and want to keep editing, edit it directly instead of restoring.
  3. In the UI, disable the 'Restore to draft' action for non-published rows.
  4. 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

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


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