{"record":{"id":"a5e7bcc8421d4ccc","repo":"amir20/dozzle","slug":"await-res-json-catch-error-res","errorCode":null,"errorMessage":"(await res.json().catch(() => ({}))).error ?? res.statusText","messagePattern":"\\(await res\\.json\\(\\)\\.catch\\(\\(\\) => \\((.+?)\\)\\)\\)\\.error \\?\\? res\\.statusText","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"assets/components/Notification/AlertCard.vue","lineNumber":221,"sourceCode":"\nasync function toggleEnabled() {\n  await fetch(withBase(`/api/notifications/rules/${alert.id}`), {\n    method: \"PATCH\",\n    headers: { \"Content-Type\": \"application/json\" },\n    body: JSON.stringify({ enabled: !alert.enabled }),\n  });\n  onUpdated?.();\n}\n\nfunction editAlert() {\n  showDrawer(AlertForm, { alert, onCreated: onUpdated }, \"lg\");\n}\n\nasync function deleteAlert() {\n  isDeleting.value = true;\n  try {\n    const res = await fetch(withBase(`/api/notifications/rules/${alert.id}`), { method: \"DELETE\" });\n    if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error ?? res.statusText);\n    confirmingDelete.value = false;\n    onUpdated?.();\n  } catch (e) {\n    showToast({ type: \"error\", message: e instanceof Error ? e.message : t(\"error.something-went-wrong\") });\n  } finally {\n    isDeleting.value = false;\n  }\n}\n</script>\n\n<style scoped>\n.card.highlight-new {\n  animation: highlight-fade 3s ease-out;\n}\n\n@keyframes highlight-fade {\n  from {\n    background-color: oklch(from var(--color-secondary) l c h / 0.25);","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/assets/components/Notification/AlertCard.vue#L203-L239","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Reload the notifications page to refresh the rule list if the status is 404 (rule already removed)","Check backend logs and ./data/notifications.yml permissions if the status is 500","Log in again if the status is 401/403","Retry the delete once connectivity to the backend is restored (proxy 5xx)"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await deleteAlert(alert.id);\n} catch (e) {\n  showToast({ type: \"error\", message: e instanceof Error ? e.message : t(\"error.something-went-wrong\") });\n}","preventionTips":["Refresh the rule list before deleting to avoid deleting an already-removed id","Ensure ./data is writable by the Dozzle process","Handle 404 as success (idempotent delete) in UI code"],"tags":["network","http-error","delete","notifications"],"backgroundTag":"http-error-response","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"}