amir20/dozzle · error · Error

(await res.json().catch(() =>

Error message

(await res.json().catch(() => ({}))).error ?? res.statusText

What it means

AlertCard.vue deletes a notification rule via DELETE /api/notifications/rules/{id}. On a non-ok response it throws an Error whose message is the backend JSON `error` field if present, otherwise res.statusText. This surfaces server-side validation errors (e.g. rule already gone, persist failure) directly into the toast.

Solutions

  1. Reload the notifications page to refresh the rule list if the status is 404 (rule already removed)
  2. Check backend logs and ./data/notifications.yml permissions if the status is 500
  3. Log in again if the status is 401/403
  4. Retry the delete once connectivity to the backend is restored (proxy 5xx)
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await deleteAlert(alert.id);
} catch (e) {
  showToast({ type: "error", message: e instanceof Error ? e.message : t("error.something-went-wrong") });
}

Prevention

When it happens

Trigger: DELETE request to /api/notifications/rules/{alert.id} returns non-2xx: the rule was already deleted in another tab (404), notifications.yml is not writable so the backend persist step fails (500), or the session expired (401).

Common situations: Two browser tabs deleting the same alert concurrently; read-only ./data volume in the container causing the persist write to fail; reverse proxy returning 502 because the backend restarted mid-request.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

Thrown at assets/components/Notification/AlertCard.vue:221

async function toggleEnabled() {
  await fetch(withBase(`/api/notifications/rules/${alert.id}`), {
    method: "PATCH",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ enabled: !alert.enabled }),
  });
  onUpdated?.();
}

function editAlert() {
  showDrawer(AlertForm, { alert, onCreated: onUpdated }, "lg");
}

async function deleteAlert() {
  isDeleting.value = true;
  try {
    const res = await fetch(withBase(`/api/notifications/rules/${alert.id}`), { method: "DELETE" });
    if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error ?? res.statusText);
    confirmingDelete.value = false;
    onUpdated?.();
  } catch (e) {
    showToast({ type: "error", message: e instanceof Error ? e.message : t("error.something-went-wrong") });
  } finally {
    isDeleting.value = false;
  }
}
</script>

<style scoped>
.card.highlight-new {
  animation: highlight-fade 3s ease-out;
}

@keyframes highlight-fade {
  from {
    background-color: oklch(from var(--color-secondary) l c h / 0.25);

View on GitHub (pinned to d9463cbe21)