{"record":{"id":"451cf1177c5a2d80","repo":"windmill-labs/windmill","slug":"cannot-deploy-label-saving-the-latest-draft-fa","errorCode":null,"errorMessage":"Cannot deploy ${label}: saving the latest draft failed (${failureMessage ?? 'unknown error'}). Retry once the draft saves.","messagePattern":"Cannot deploy (.+?): saving the latest draft failed \\((.+?)\\)\\. Retry once the draft saves\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/copilot/chat/global/core.ts","lineNumber":7233,"sourceCode":"\n// Flush a draft's pending editor autosave, then verify it actually landed before\n// the caller re-reads the persisted draft. `flush()` resolves even when the save\n// recorded a conflict (server has a newer version) or failed (network/5xx) — it\n// does not throw — so without this check a deploy could publish a stale/conflicting\n// draft. Abort with a clear message instead.\nasync function flushDraftOrThrow(\n\tquery: Parameters<typeof UserDraftDbSyncer.flush>[0],\n\tlabel: string\n): Promise<void> {\n\tawait UserDraftDbSyncer.flush(query)\n\tif (UserDraftDbSyncer.getConflict(query).conflict) {\n\t\tthrow new Error(\n\t\t\t`Cannot deploy ${label}: the draft has a conflicting newer version on the server. Open it in the editor and resolve the conflict first.`\n\t\t)\n\t}\n\tconst { state, failureMessage } = UserDraftDbSyncer.getState(query)\n\tif (state === 'failed') {\n\t\tthrow new Error(\n\t\t\t`Cannot deploy ${label}: saving the latest draft failed (${failureMessage ?? 'unknown error'}). Retry once the draft saves.`\n\t\t)\n\t}\n}\n\nasync function deployDraft(\n\targs: {\n\t\ttype: WorkspaceItemType\n\t\tpath: string\n\t\ttrigger_kind?: TriggerKind\n\t\tdeployment_message?: string\n\t\tforce?: boolean\n\t},\n\tctx: WriteDraftCtx\n): Promise<string> {\n\tconst { workspace, toolId, toolCallbacks, sessionId } = ctx\n\tconst {\n\t\ttype,","sourceCodeStart":7215,"sourceCodeEnd":7251,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/copilot/chat/global/core.ts#L7215-L7251","documentation":"Thrown by flushDraftOrThrow when, after flushing the draft to the server, UserDraftDbSyncer.getState(query) reports state 'failed'. This means the draft save itself failed (e.g. validation or a network/server error), and deploying would ship a stale or unknown version. The failureMessage from the syncer, when present, is embedded in the error; otherwise 'unknown error' is used. The deploy is blocked until the draft saves successfully.","triggerScenarios":"Calling the chat's deploy tool when the pending draft flush failed: UserDraftDbSyncer.getState(query).state === 'failed' after UserDraftDbSyncer.flush(query), with an optional failureMessage carried on the sync state.","commonSituations":"The browser lost connectivity mid-save; the server rejected the draft save (schema/validation failure); a transient 5xx during autosave; the item was deleted server-side while a draft existed locally.","solutions":["Read the embedded failureMessage to see why the save failed and fix that cause (e.g. restore network, fix validation).","Retry the deploy once the draft saves successfully (the error explicitly says to wait for the save to complete).","If the save keeps failing, open the draft in the editor and re-save manually to see the full server error."],"exampleFix":"// before\nawait deployDraft({ type: 'flow', path: 'f/etl' })\n// Error: Cannot deploy flow \"f/etl\": saving the latest draft failed (network timeout). Retry once the draft saves.\n\n// after: reconnect / fix the save, confirm draft state is 'saved', then retry\nawait deployDraft({ type: 'flow', path: 'f/etl' }) // succeeds","handlingStrategy":"retry","validationCode":"import { UserDraftDbSyncer } from '$lib/components/copilot/chat/global/userDraftSyncer'\nconst { state } = UserDraftDbSyncer.getState(query)\nif (state !== 'saved') {\n  // wait for the draft save to settle before deploying\n}","typeGuard":"function isDraftSaveFailed(query) {\n  const { state } = UserDraftDbSyncer.getState(query)\n  return state === 'failed'\n}","tryCatchPattern":"try {\n  await deployDraft(args)\n} catch (e) {\n  if (/saving the latest draft failed/.test(e.message)) {\n    // check e.message for failureMessage, fix connectivity/validation, then retry\n  } else throw e\n}","preventionTips":["Ensure a stable connection before running agent-driven deploys.","Check the draft save state before issuing a deploy.","Address the failureMessage cause (validation, permissions) before retrying."],"tags":["draft-sync","network","save-failed","deploy"],"backgroundTag":"draft-save-failed","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}