{"record":{"id":"69e650bab71674dd","repo":"amir20/dozzle","slug":"cloud-dispatcher-missing","errorCode":null,"errorMessage":"cloud dispatcher missing","messagePattern":"cloud dispatcher missing","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"assets/components/WelcomeModal.vue","lineNumber":553,"sourceCode":"  const chosen = activeRules.value;\n  if (chosen.length === 0) {\n    createdCount.value = 0;\n    reportUsage(true);\n    step.value = 3;\n    return;\n  }\n\n  creating.value = true;\n  abortController?.abort();\n  abortController = new AbortController();\n  const signal = abortController.signal;\n\n  try {\n    const dispatchersRes = await fetch(withBase(\"/api/notifications/dispatchers\"), { signal });\n    if (!dispatchersRes.ok) throw new Error(\"dispatchers fetch failed\");\n    const dispatchers: Array<{ id: number; type: string }> = await dispatchersRes.json();\n    const cloud = dispatchers.find((d) => d.type === \"cloud\");\n    if (!cloud) throw new Error(\"cloud dispatcher missing\");\n\n    // Fire rule POSTs in parallel. Partial failure is not cleaned up — if one\n    // rejects, the earlier ones are already saved and the user lands on the\n    // fallback toast path. Acceptable for a welcome modal; the user can edit\n    // or delete rules from /notifications.\n    await Promise.all(\n      chosen.map((rule) =>\n        fetch(withBase(\"/api/notifications/rules\"), {\n          method: \"POST\",\n          headers: { \"Content-Type\": \"application/json\" },\n          signal,\n          body: JSON.stringify({\n            name: rule.ruleName,\n            enabled: true,\n            dispatcherId: cloud.id,\n            containerExpression: \"true\",\n            logExpression: rule.kind === \"log\" ? rule.expression : \"\",\n            eventExpression: rule.kind === \"event\" ? rule.expression : \"\",","sourceCodeStart":535,"sourceCodeEnd":571,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/assets/components/WelcomeModal.vue#L535-L571","documentation":"WelcomeModal.vue throws this when the dispatchers list loads successfully but contains no entry with type === 'cloud'. The rule-creation flow requires a cloud dispatcher to route alerts through and refuses to continue without one.","triggerScenarios":"GET /api/notifications/dispatchers returns a list whose `type` values never equal \"cloud\" (only email/webhook/etc.), or an empty list.","commonSituations":"User never linked Dozzle Cloud (no cloud dispatcher provisioned), running a build where the dispatcher type string was renamed, or the cloud plugin/dispatcher failed to register server-side.","solutions":["Link Dozzle Cloud first so the cloud dispatcher is provisioned, then retry the setup","Check GET /api/notifications/dispatchers output to see which dispatcher types actually exist","Verify the expected type string is exactly \"cloud\" against the backend dispatcher factory","Guard the flow: show a setup step for linking Cloud instead of throwing mid-way"],"exampleFix":"// before\nconst cloud = dispatchers.find((d) => d.type === \"cloud\");\nif (!cloud) throw new Error(\"cloud dispatcher missing\");\n// after\nconst cloud = dispatchers.find((d) => d.type === \"cloud\");\nif (!cloud) {\n  showToast({ type: \"warning\", message: t(\"notifications.cloud-not-linked\") });\n  return; // or redirect to Cloud linking step\n}","handlingStrategy":"fallback","validationCode":"const dispatchers: Array<{ id: number; type: string }> = await dispatchersRes.json();\nconst hasCloud = dispatchers.some((d) => d.type === \"cloud\");\nif (!hasCloud) { /* show cloud-linking step instead of proceeding */ }","typeGuard":"function isCloudDispatcher(d: { type: string }): boolean {\n  return d.type === \"cloud\";\n}","tryCatchPattern":"try {\n  setupRulesWithCloud(cloud);\n} catch (e) {\n  if (e instanceof Error && e.message === \"cloud dispatcher missing\") {\n    showCloudLinkStep(); // graceful fallback instead of a dead-end toast\n  }\n}","preventionTips":["Link Dozzle Cloud before offering the welcome-modal alert setup","Gate the alert-creation UI on a 'cloud linked' check","Assert the dispatcher type string against the backend enum when upgrading versions"],"tags":["notifications","vue","cloud","missing-entity"],"backgroundTag":"entity-not-found","analyzedSha":"d9463cbe21874e44ab79db6fa63e746ca7d22928","analyzedAt":"2026-09-07T10:08:55.855Z","contentChangedAt":"2026-09-07T10:08:55.855Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}