{"record":{"id":"d5e65189a679b207","repo":"windmill-labs/windmill","slug":"could-not-synthesize-type-draft-path","errorCode":null,"errorMessage":"Could not synthesize ${type} draft \"${path}\".","messagePattern":"Could not synthesize (.+?) draft \"(.+?)\"\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/copilot/chat/global/userDraftAdapter.ts","lineNumber":439,"sourceCode":"\tconst itemKind = itemKindFor(type, opts.triggerKind)\n\tif (!itemKind) throw new Error(`Unsupported draft type \"${type}\".`)\n\tconst storagePath = resolveDraftStoragePath(workspace, itemKind, path)\n\tUserDraft.seed(itemKind, storagePath, value, { workspace })\n\tawait UserDraftDbSyncer.save({\n\t\tworkspace,\n\t\titemKind,\n\t\tpath: storagePath,\n\t\tvalue,\n\t\timmediate: true,\n\t\tforce: opts.force\n\t})\n\tconst { displayPath, isLiveDraft } = liveDisplayPath(workspace, itemKind, storagePath)\n\tconst item = userDraftEntryToWorkspaceItem(\n\t\t{ workspace, itemKind, path: storagePath, value },\n\t\tdisplayPath,\n\t\tisLiveDraft\n\t)\n\tif (!item) throw new Error(`Could not synthesize ${type} draft \"${path}\".`)\n\t// A failed save (network/5xx) is recorded in the syncer's failure map, not\n\t// thrown — so check it before reporting success, else a write tool would tell\n\t// the chat \"saved\" while the DB-backed source of truth was never updated.\n\tconst saveState = UserDraftDbSyncer.getState({ workspace, itemKind, path: storagePath })\n\tif (saveState.state === 'failed') {\n\t\treturn {\n\t\t\tstatus: 'error',\n\t\t\titem,\n\t\t\titemKind,\n\t\t\tstoragePath,\n\t\t\tmessage: saveState.failureMessage ?? 'Draft save failed'\n\t\t}\n\t}\n\tconst conflict = opts.force\n\t\t? undefined\n\t\t: UserDraftDbSyncer.getConflict({ workspace, itemKind, path: storagePath }).conflict\n\tif (conflict) {\n\t\treturn {","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/copilot/chat/global/userDraftAdapter.ts#L421-L457","documentation":"After storing the draft value, persistGlobalDraft converts the stored UserDraftEntry back into a chat WorkspaceItem via userDraftEntryToWorkspaceItem(). That converter dispatches on itemKind and delegates to per-kind converters (scriptDraftToWorkspaceItem, flowDraftToWorkspaceItem, ...) which return undefined when the value does not match the expected shape for that kind. If no WorkspaceItem can be synthesized, this error is thrown — the in-memory seed is then already dirty, so callers should treat it as an internal consistency failure.","triggerScenarios":"persistGlobalDraft called with a value whose shape fails the per-kind converter (e.g. a script draft value missing the fields scriptDraftToWorkspaceItem requires, a malformed app/flow value); or an itemKind that has no converter (chat-unaddressable kinds like webhook/poll/cli trigger drafts reaching the write path).","commonSituations":"An AI chat write tool receives a loosely-typed JSON 'value' argument from the model and forwards it unvalidated; version drift where a converter was tightened but callers still send the old shape.","solutions":["Validate the draft value against the kind's expected shape (NewScript, Flow, AppDraftValue, ResourceDraftState, etc.) before calling persistGlobalDraft.","Log entry.itemKind and the value when this fires to see which converter returned undefined.","If type is a trigger, ensure its draft kind is chat-addressable (has an entry in TRIGGER_KIND_BY_DRAFT_KIND) and the value matches TriggerRequestBody.","Extend the corresponding xxxDraftToWorkspaceItem converter if a legitimate new shape was rejected."],"exampleFix":"// before\nawait persistGlobalDraft(ws, 'script', path, value)\n// after\nif (!value || typeof value !== 'object' || !('content' in value)) throw new Error('Invalid script draft value')\nawait persistGlobalDraft(ws, 'script', path, value)","handlingStrategy":"validation","validationCode":"function isPlausibleDraftValue(type: WorkspaceItemType, value: unknown): boolean {\n  return typeof value === 'object' && value !== null && Object.keys(value).length > 0\n}\nif (!isPlausibleDraftValue(type, value)) throw new Error(`Malformed ${type} draft value`)","typeGuard":"function isRecord(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v)\n}","tryCatchPattern":"try {\n  await persistGlobalDraft(workspace, type, path, value, opts)\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Could not synthesize')) {\n    console.error('Draft value rejected by converter', { type, path, value })\n    notify(`The ${type} draft value is not in the expected format`)\n  } else throw e\n}","preventionTips":["Validate model-produced draft values against the kind's schema (NewScript, Flow, etc.) before persisting","Log the offending value when converters return undefined to catch shape drift early","Keep xxxDraftToWorkspaceItem converters and their input types co-located so changes stay in sync"],"tags":["typescript","data-shape","internal-invariant"],"backgroundTag":"draft-value-shape-mismatch","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"}