amir20/dozzle · error · Error

dispatchers fetch failed

Error message

dispatchers fetch failed

What it means

WelcomeModal.vue throws this when GET /api/notifications/dispatchers returns a non-ok response during the welcome-modal setup flow. The modal aborts creating notification rules because it cannot determine whether a cloud dispatcher exists.

Solutions

  1. Distinguish AbortError from real HTTP failures and skip the toast on user-initiated aborts
  2. Log res.status and the response body to identify the server-side reason
  3. Verify the user is authenticated before opening the modal flow
  4. On deployments without notification support, hide or skip this welcome setup step

Example fix

// before
if (!dispatchersRes.ok) throw new Error("dispatchers fetch failed");
// after
if (!dispatchersRes.ok) {
  if (signal.aborted) return; // user closed the modal, not a real failure
  throw new Error(`dispatchers fetch failed (HTTP ${dispatchersRes.status})`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (signal.aborted) return;
const res = await fetch(withBase("/api/notifications/dispatchers"), { signal });

Type guard

function isAbortError(e: unknown): e is DOMException {
  return e instanceof DOMException && e.name === "AbortError";
}

Try / catch

try {
  const res = await fetch(url, { signal });
  if (!res.ok) throw new Error(`dispatchers fetch failed (HTTP ${res.status})`);
} catch (e) {
  if (isAbortError(e) || signal.aborted) return; // user closed modal
  showToast({ type: "error", message: String(e) });
}

Prevention

When it happens

Trigger: GET /api/notifications/dispatchers fails with 4xx/5xx or is rejected before completion (note the AbortController signal): auth failure, server error, or the request being aborted when the modal is closed/unmounted.

Common situations: User closes the welcome modal mid-setup (AbortController aborts, surfaces as an error here); expired session; notifications API unavailable on k8s/agent deployments without a notification manager.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07). Data as JSON: /api/errors/faefee58ca567db1. Report an issue: GitHub.

Appendix: source

Thrown at assets/components/WelcomeModal.vue:550

async function createAlerts() {
  if (creating.value) return;
  const chosen = activeRules.value;
  if (chosen.length === 0) {
    createdCount.value = 0;
    reportUsage(true);
    step.value = 3;
    return;
  }

  creating.value = true;
  abortController?.abort();
  abortController = new AbortController();
  const signal = abortController.signal;

  try {
    const dispatchersRes = await fetch(withBase("/api/notifications/dispatchers"), { signal });
    if (!dispatchersRes.ok) throw new Error("dispatchers fetch failed");
    const dispatchers: Array<{ id: number; type: string }> = await dispatchersRes.json();
    const cloud = dispatchers.find((d) => d.type === "cloud");
    if (!cloud) throw new Error("cloud dispatcher missing");

    // Fire rule POSTs in parallel. Partial failure is not cleaned up — if one
    // rejects, the earlier ones are already saved and the user lands on the
    // fallback toast path. Acceptable for a welcome modal; the user can edit
    // or delete rules from /notifications.
    await Promise.all(
      chosen.map((rule) =>
        fetch(withBase("/api/notifications/rules"), {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          signal,
          body: JSON.stringify({
            name: rule.ruleName,
            enabled: true,
            dispatcherId: cloud.id,

View on GitHub (pinned to d9463cbe21)