{"record":{"id":"95e001f49af650b1","repo":"windmill-labs/windmill","slug":"unexpected-trigger-kind-got-kind","errorCode":null,"errorMessage":"Unexpected trigger kind got: ${kind}","messagePattern":"Unexpected trigger kind got: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/src/lib/utils_deployable.ts","lineNumber":352,"sourceCode":"\t\t}\n\t} else if (kind === 'schedules') {\n\t\tconst schedulesTrigger = await ScheduleService.getSchedule({\n\t\t\tworkspace: workspace!,\n\t\t\tpath: path\n\t\t})\n\t\treturn {\n\t\t\tdata: {\n\t\t\t\t...schedulesTrigger,\n\t\t\t\t// permissioned_as is only set on create, not update\n\t\t\t\tpermissioned_as: onBehalfOf,\n\t\t\t\tpreserve_permissioned_as: preservePermissionedAs\n\t\t\t},\n\t\t\tcreateFn: ScheduleService.createSchedule,\n\t\t\tupdateFn: ScheduleService.updateSchedule\n\t\t}\n\t}\n\n\tthrow new Error(`Unexpected trigger kind got: ${kind}`)\n}\n\n/**\n * Runtime fields stripped from the trigger/schedule diff so the drawer mirrors\n * the backend's `compare_two_trigger_or_schedule` semantics — same set as\n * `TRIGGER_COMPARE_IGNORE` and `stripTriggerOrScheduleRuntimeFields` in the\n * shared deploy module.\n */\nexport const TRIGGER_RUNTIME_IGNORE = new Set([\n\t'workspace_id',\n\t'edited_by',\n\t'edited_at',\n\t'email',\n\t'error',\n\t'enabled',\n\t'mode',\n\t'server_id',\n\t'last_server_ping',","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/utils_deployable.ts#L334-L370","documentation":"getTriggersDeployData in frontend/src/lib/utils_deployable.ts (line 352) resolves, for a given TriggerKind, the trigger's current data plus the createFn/updateFn service methods used to deploy it. It handles only the 12 deployable trigger kinds; any other TriggerKind value (e.g. UI-only kinds like 'webhooks', 'cli', 'scheduledPoll', 'nextcloud', 'google', 'github', 'default_emails') reaches the terminal throw. This is an internal exhaustiveness guard for the workspace deploy flow.","triggerScenarios":"Calling getTriggersDeployData(kind, path, workspace) during deployment of a workspace item whose kind is not one of sqs, kafka, mqtt, amqp, nats, gcp, postgres, websockets, routes, azure, emails, schedules — typically 'webhooks' or 'cli' coming from a trigger list, or a misspelled kind string.","commonSituations":"Deploying a workspace containing non-capture trigger types whose kind leaks into the trigger-deploy loop; a new trigger kind added to TriggerKind but not to this dispatcher; a kind mapping change between the backend compare API naming ('schedules' vs 'schedule') and the frontend.","solutions":["Log/inspect the `kind` value in the error and confirm it is one of the 12 supported trigger kinds; correct the caller if it passes e.g. 'webhooks' or 'schedule' (should be 'schedules').","If the item genuinely is not a deployable trigger kind, filter it out of the deploy loop before calling getTriggersDeployData.","If you introduced a new trigger kind, add an `else if` branch that fetches the trigger via its Service.get* and returns its Service.create*/update* pair.","Ensure the kind string is normalized from backend item types ('http_trigger' → 'routes', etc.) before dispatch."],"exampleFix":"// before\nconst { data, createFn, updateFn } = await getTriggersDeployData('schedule', path, workspace)\n// after\nconst { data, createFn, updateFn } = await getTriggersDeployData('schedules', path, workspace)","handlingStrategy":"validation","validationCode":"const DEPLOY_KINDS = ['sqs','kafka','mqtt','amqp','nats','gcp','postgres','websockets','routes','azure','emails','schedules'] as const\nif (!(DEPLOY_KINDS as readonly string[]).includes(kind)) {\n  console.warn(`Skipping deploy data for non-deployable trigger kind ${kind}`)\n  return\n}\nconst deployData = await getTriggersDeployData(kind, path, workspace)","typeGuard":"const DEPLOY_KINDS = ['sqs','kafka','mqtt','amqp','nats','gcp','postgres','websockets','routes','azure','emails','schedules'] as const\ntype DeployableTriggerKind = (typeof DEPLOY_KINDS)[number]\nfunction isDeployableTriggerKind(k: string): k is DeployableTriggerKind {\n  return (DEPLOY_KINDS as readonly string[]).includes(k)\n}","tryCatchPattern":"try {\n  const { data, createFn, updateFn } = await getTriggersDeployData(kind, path, workspace)\n} catch (e) {\n  if (String(e?.message).startsWith('Unexpected trigger kind got:')) {\n    // skip this item in the deploy loop and report it at the end\n  } else throw e\n}","preventionTips":["Filter the item list to deployable trigger kinds before the deploy loop, not inside it.","Keep kind normalization (backend item type → TriggerKind) in one shared helper.","Add a unit test enumerating every TriggerKind member and asserting which dispatcher handles it."],"tags":["frontend","typescript","trigger","deployment","dispatch"],"backgroundTag":"unsupported-trigger-kind","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"}