{"record":{"id":"fe5a1da39e224ff4","repo":"amir20/dozzle","slug":"preview-failed","errorCode":null,"errorMessage":"Preview failed","messagePattern":"Preview failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"assets/composable/alertForm.ts","lineNumber":132,"sourceCode":"  async function validatePreview(extraFields: Record<string, unknown> = {}) {\n    if (!containerExpression.value && !Object.values(extraFields).some(Boolean)) {\n      containerResult.value = null;\n      return { data: null };\n    }\n\n    isLoading.value = true;\n    try {\n      const res = await fetch(withBase(\"/api/notifications/preview\"), {\n        method: \"POST\",\n        headers: { \"Content-Type\": \"application/json\" },\n        body: JSON.stringify({\n          containerExpression: containerExpression.value,\n          ...extraFields,\n        }),\n      });\n      if (!res.ok) {\n        const errData = await res.json();\n        throw new Error(errData.error || \"Preview failed\");\n      }\n      const data: PreviewResult = await res.json();\n      containerResult.value = containerExpression.value\n        ? {\n            error: data.containerError ?? undefined,\n            containers: data.matchedContainers?.map((c) => Container.fromJSON(c as ContainerJson)),\n          }\n        : null;\n      return { data };\n    } catch (e) {\n      containerResult.value = { error: e instanceof Error ? e.message : \"Unknown error\" };\n      return { data: null };\n    } finally {\n      isLoading.value = false;\n    }\n  }\n\n  return {","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/assets/composable/alertForm.ts#L114-L150","documentation":"validatePreview() POSTs the alert expression to the preview endpoint to see which containers would match before saving. If the response is not ok, it throws \"Preview failed\", or the server's error field if provided. Unlike saveAlert, it is called from inside the form flow, so a throw here surfaces as an unhandled rejection unless the caller catches it.","triggerScenarios":"Calling validatePreview() with a containerExpression or log query the preview endpoint rejects with a non-2xx status: invalid regex, malformed expression syntax, missing required fields in extraFields, or a 500 from the backend while evaluating the expression against containers.","commonSituations":"Typing an invalid regex pattern into the expression box and hitting preview; previewing before any containers are selected; backend errors because the preview route is unavailable (proxy misconfiguration or older backend without the preview endpoint returning 404).","solutions":["Check the server error text (errData.error) — for regex/expression failures it names the invalid syntax; correct the expression before previewing.","Validate the expression client-side before calling: compile the regex or expression and bail out early on parse failure.","Confirm the preview API route exists and the request URL/base path is correct (a 404 here usually means a proxy or version mismatch).","Wrap the preview call in try/catch and show the message in the form instead of letting it throw."],"exampleFix":"// before\nawait validatePreview(); // unhandled throw on bad regex\n// after\nif (containerExpression.value) {\n  try { new RegExp(logExpression.value); } catch (e) {\n    previewError.value = \"Invalid regex: \" + e.message;\n    return;\n  }\n  await validatePreview();\n}","handlingStrategy":"try-catch","validationCode":"// pre-validate expression before preview\nlet regexOk = true;\ntry { new RegExp(logExpression.value); } catch { regexOk = false; }\nif (!regexOk) return; // skip validatePreview","typeGuard":null,"tryCatchPattern":"try {\n  await validatePreview();\n} catch (e) {\n  previewError.value = e instanceof Error ? e.message : \"Preview failed\";\n}","preventionTips":["Compile user-supplied regexes client-side before any network call.","Always render preview errors inline in the form instead of letting them throw.","Confirm the preview endpoint is reachable (correct base path/proxy) during setup.","Debounce preview calls so rapid typing does not race the endpoint."],"tags":["network","http","preview","regex"],"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"}