{"record":{"id":"80d361d5c83268e0","repo":"langgenius/dify","slug":"draft-workflow-not-sync","errorCode":"draft_workflow_not_sync","errorMessage":"Workflow graph might have been modified, please refresh and resubmit.","messagePattern":"Workflow graph might have been modified, please refresh and resubmit\\.","errorType":"error_code","errorClass":"DraftWorkflowNotSync","httpStatus":409,"severity":"warning","filePath":"api/controllers/console/app/workflow.py","lineNumber":672,"sourceCode":"                variable_factory.build_conversation_variable_from_mapping(obj)\n                for obj in args_model.conversation_variables\n            ]\n            workflow = workflow_service.sync_draft_workflow(\n                app_model=app_model,\n                graph=args_model.graph,\n                features=args_model.features,\n                unique_hash=args_model.hash,\n                account=current_user,\n                environment_variables=[],\n                conversation_variables=conversation_variables,\n                session=db.session(),\n                environment_variable_upserts=environment_variable_upserts,\n                deleted_environment_variable_ids=deleted_environment_variable_ids,\n                preserve_environment_variables=True,\n                graph_only=args_model.is_collaborative,\n            )\n        except WorkflowHashNotEqualError:\n            raise DraftWorkflowNotSync()\n        except VariableError as e:\n            raise InvalidArgumentError(description=str(e))\n\n        return dump_response(\n            SyncDraftWorkflowResponse,\n            {\n                \"result\": \"success\",\n                \"hash\": workflow.unique_hash,\n                \"updated_at\": TimestampField().format(workflow.updated_at or workflow.created_at),\n            },\n        )\n\n\n@console_ns.route(\"/apps/<uuid:app_id>/advanced-chat/workflows/draft/run\")\nclass AdvancedChatDraftWorkflowRunApi(Resource):\n    @console_ns.doc(\"run_advanced_chat_draft_workflow\")\n    @console_ns.doc(description=\"Run draft workflow for advanced chat application\")\n    @console_ns.doc(params={\"app_id\": \"Application ID\"})","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/app/workflow.py#L654-L690","documentation":"Raised as DraftWorkflowNotSync when WorkflowService.sync_draft_workflow raises WorkflowHashNotEqualError (api/controllers/console/app/workflow.py:671-672). The client-supplied hash (SyncDraftWorkflowPayload.hash) does not match the server's current draft hash, meaning the draft was modified since the client last loaded it. The server refuses the sync to prevent a blind overwrite of concurrent changes.","triggerScenarios":"POSTing a draft-workflow sync with a stale hash — another user/session saved the same draft after the client loaded it, or the same client saved in another tab. The hash mismatch triggers WorkflowHashNotEqualError inside sync_draft_workflow.","commonSituations":"Collaborative editing with two editors; same user editing in two tabs; long idle between load and save where an autosave/another session changed the graph; client using an outdated cached hash after a reconnect.","solutions":["GET the current draft workflow to obtain the latest hash and graph, reconcile local edits, then re-POST with the fresh hash.","Use collaborative mode (is_collaborative / _is_collaborative) if supported, to coordinate concurrent edits.","Avoid keeping a draft open and unsaved across long idle periods; save promptly.","Surface this error to the user as 'refresh required' and merge or discard local changes explicitly."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Load the latest hash right before sync to reduce staleness\nconst fresh = await getDraftWorkflow(appId)\npayload.hash = fresh.hash\nawait syncDraft(appId, payload)","typeGuard":null,"tryCatchPattern":"try {\n  await syncDraft(appId, payload)\n} catch (e) {\n  if (e.code === 'draft_workflow_not_sync') {\n    const fresh = await getDraftWorkflow(appId)\n    payload.hash = fresh.hash\n    // merge or discard local edits, then retry once\n    return syncDraft(appId, payload)\n  }\n  throw e\n}","preventionTips":["Sync promptly after loading to shrink the staleness window.","Refresh before retry; never retry with the same stale hash.","Use collaborative mode for multi-editor workflows."],"tags":["workflow","draft","concurrency","hash-mismatch","optimistic-lock","api"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}