langgenius/dify · error · DraftWorkflowNotExist

draft_workflow_not_exist

draft_workflow_not_exist

Error message

Draft workflow need to be initialized.

What it means

Returned (HTTP 404, `draft_workflow_not_exist`, 'Draft workflow need to be initialized.') by GET /rag/pipelines/<pipeline_id>/workflows/draft when `RagPipelineService.get_draft_workflow(pipeline)` is falsy. The draft workflow is the editable working copy of the pipeline graph; if it has never been created the endpoint cannot return one.

Source

Thrown at api/controllers/console/datasets/rag_pipeline/rag_pipeline_workflow.py:205

        console_ns.models[WorkflowResponse.__name__],
    )
    @console_ns.response(404, "Draft workflow not found")
    @setup_required
    @login_required
    @account_initialization_required
    @get_rag_pipeline
    @edit_permission_required
    @rbac_permission_required(RBACResourceScope.DATASET, RBACPermission.DATASET_EDIT)
    def get(self, pipeline: Pipeline):
        """
        Get draft rag pipeline's workflow
        """
        # fetch draft workflow by app_model
        rag_pipeline_service = RagPipelineService(db.session())
        workflow = rag_pipeline_service.get_draft_workflow(pipeline=pipeline)

        if not workflow:
            raise DraftWorkflowNotExist()

        # return workflow, if not found, return 404
        return dump_response(WorkflowResponse, workflow)

    @setup_required
    @login_required
    @account_initialization_required
    @with_current_user
    @get_rag_pipeline
    @edit_permission_required
    @rbac_permission_required(RBACResourceScope.DATASET, RBACPermission.DATASET_EDIT)
    @console_ns.expect(console_ns.models[DraftWorkflowSyncPayload.__name__])
    @console_ns.response(200, "Success", console_ns.models[RagPipelineWorkflowSyncResponse.__name__])
    def post(self, current_user: Account, pipeline: Pipeline):
        """
        Sync draft workflow
        """
        content_type = request.headers.get("Content-Type", "")

View on GitHub (pinned to ef8544b173)

Solutions

  1. Initialize the draft via POST /rag/pipelines/<pipeline_id>/workflows/draft with the starter graph.
  2. If a published workflow exists, POST /rag/pipelines/<pipeline_id>/workflows/<workflow_id>/restore to recreate the draft.
  3. Handle 404 with code `draft_workflow_not_exist` in the client by showing an initialization screen.
  4. Audit pipeline creation flows to ensure a draft is always seeded.

Example fix

// before
const draft = await get(`/rag/pipelines/${pid}/workflows/draft`)
// after
let draft = await get(`/rag/pipelines/${pid}/workflows/draft`).catch(e => {
  if (e.code !== 'draft_workflow_not_exist') throw e
  return null
})
if (!draft) {
  await post(`/rag/pipelines/${pid}/workflows/draft`, { graph: emptyGraph })
  draft = await get(`/rag/pipelines/${pid}/workflows/draft`)
}
Defensive patterns

Strategy: try-catch

Validate before calling

async function getOrInitDraft(pid) {
  const r = await fetch(`/rag/pipelines/${pid}/workflows/draft`)
  if (r.status === 404) {
    await post(`/rag/pipelines/${pid}/workflows/draft`, { graph: starterGraph })
    return fetch(`/rag/pipelines/${pid}/workflows/draft`).then(r => r.json())
  }
  if (!r.ok) throw new Error(`unexpected ${r.status}`)
  return r.json()
}

Try / catch

try {
  return await get(`${base}/draft`)
} catch (e) {
  if (e.code === 'draft_workflow_not_exist') {
    // initialize or restore-from-published, then retry once
  } else throw e
}

Prevention

When it happens

Trigger: Opening the pipeline editor for a brand-new pipeline before any graph has been synced; pipeline whose draft was deleted; restored/published-only pipeline that has no draft.

Common situations: Pipeline created via API without a follow-up draft sync. Database restore that omitted the workflows table. Multi-step onboarding that loads the editor before initialization.

Related errors


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