{"record":{"id":"f5f24cd047ecd47c","repo":"amir20/dozzle","slug":"await-res-json-catch-error-res-f5f24c","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/DestinationCard.vue","lineNumber":170,"sourceCode":"    const candidate = `${base} ${i}`;\n    if (!taken.has(candidate)) return candidate;\n  }\n}\n\nasync function duplicateDestination() {\n  try {\n    const res = await fetch(withBase(\"/api/notifications/dispatchers\"), {\n      method: \"POST\",\n      headers: { \"Content-Type\": \"application/json\" },\n      body: JSON.stringify({\n        name: copyName(),\n        type: destination.type,\n        url: destination.url,\n        template: destination.template,\n        headers: destination.headers,\n      }),\n    });\n    if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error ?? res.statusText);\n    onUpdated?.();\n  } catch (e) {\n    showToast({ type: \"error\", message: e instanceof Error ? e.message : t(\"notifications.destination.copy-failed\") });\n  }\n}\n\nasync function deleteDestination() {\n  isDeleting.value = true;\n  try {\n    const res = await fetch(withBase(`/api/notifications/dispatchers/${destination.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({\n      type: \"error\",\n      message: e instanceof Error ? e.message : t(\"notifications.destination.delete-failed\"),\n    });","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/assets/components/Notification/DestinationCard.vue#L152-L188","documentation":"DestinationCard.vue saves a notification destination via a POST/PUT fetch to the notifications API. When res.ok is false it throws an Error built from the backend JSON `error` field, falling back to res.statusText, which the catch block shows as a toast. The backend returns structured errors for invalid webhook URLs, unreachable destinations, or persistence failures.","triggerScenarios":"Saving a destination whose POST /api/notifications/destinations (or similar) returns non-2xx: malformed destination.url, invalid headers JSON, backend cannot persist to ./data/notifications.yml, or an expired session yields 401.","commonSituations":"Typo in webhook URL so the backend rejects validation; custom template with bad syntax rejected by server; read-only data directory causing persist failure; proxy returning 504 on slow destination test.","solutions":["Read the toast/JSON error field for the server-side reason and fix the destination url/template/headers accordingly","Verify the destination URL is reachable and uses http/https","Check ./data directory writability and backend logs if persist errors appear","Re-authenticate if the status is 401/403, then resubmit the form"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"new URL(destination.url); // throws on malformed url\nif (destination.url && !/^https?:\\/\\//.test(destination.url)) {\n  throw new Error(\"Destination url must use http or https\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  await saveDestination(destination);\n} catch (e) {\n  showToast({ type: \"error\", message: e instanceof Error ? e.message : t(\"notifications.destination.copy-failed\") });\n}","preventionTips":["Validate destination.url format client-side before submitting","Send headers as a proper JSON object, not a raw string","Ensure the data directory is writable so the backend persist step succeeds"],"tags":["network","http-error","notifications","form-submit"],"backgroundTag":"api-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"}