{"record":{"id":"95b7001eb84f4730","repo":"louislam/uptime-kuma","slug":"msg","errorCode":null,"errorMessage":"${msg}","messagePattern":"\\$\\{msg\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/notification-providers/notification-provider.js","lineNumber":167,"sourceCode":"            agg = error.cause;\n        }\n\n        if (agg) {\n            let causes = agg.errors\n                .map((e) => {\n                    let m = e && e.message ? e.message : String(e);\n                    if (e && e.code) {\n                        m += ` (code=${e.code})`;\n                    }\n                    return m;\n                })\n                .join(\"; \");\n            msg += \" - caused by: \" + causes;\n        } else if (error && error.cause && error.cause.message) {\n            msg += \" - cause: \" + error.cause.message;\n        }\n\n        throw new Error(msg);\n    }\n\n    /**\n     * Returns axios config with proxy agent if proxy env is set.\n     * @param {object} axiosConfig - Axios config containing params\n     * @returns {object} Axios config\n     */\n    getAxiosConfigWithProxy(axiosConfig = {}) {\n        const proxyEnv = process.env.notification_proxy || process.env.NOTIFICATION_PROXY;\n        if (proxyEnv) {\n            const proxyUrl = new URL(proxyEnv);\n\n            if (proxyUrl.protocol === \"http:\") {\n                axiosConfig.httpAgent = new HttpProxyAgent(proxyEnv);\n                axiosConfig.httpsAgent = new HttpsProxyAgent(proxyEnv);\n            } else if (proxyUrl.protocol === \"https:\") {\n                const agent = new HttpsProxyAgent(proxyEnv);\n                axiosConfig.httpAgent = agent;","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/notification-providers/notification-provider.js#L149-L185","documentation":"This is the terminal throwGeneralAxiosError(error) throw inside the base NotificationProvider class. It builds a single human-readable string from an axios/error: starts from error.message, appends (code=...) for error.code (e.g. ECONNREFUSED), (HTTP <status> <statusText>) when error.response exists, the response body (stringified if object), and expands AggregateError/cause chains (' - caused by: ...' / ' - cause: ...'). Nearly every provider's catch block calls this method, so this is the common funnel for all notification failures.","triggerScenarios":"Any provider that does this.throwGeneralAxiosError(error) in its catch routes here: network errors (ENOTFOUND, ECONNREFUSED, ETIMEDOUT, EAI_AGAIN), axios non-2xx rejections (error.response.status), TLS/cert errors, SOCKS/HTTP proxy errors (via getAxiosConfigWithProxy), or AggregateError from Promise.allSettled-style failures.","commonSituations":"Notification target unreachable; DNS failure for the provider hostname; self-signed/expired cert on the target; proxy env (notification_proxy / NOTIFICATION_PROXY) misconfigured; provider returned 4xx/5xx with a body that gets appended to the message.","solutions":["Read the full message: a (code=...) suffix indicates a socket/DNS failure; an (HTTP <n>) suffix indicates the server responded but with an error status.","For code=ENV... or proxy-related text, verify process.env.NOTIFICATION_PROXY / notification_proxy is a valid URL with a supported scheme (http, https, socks5).","For HTTP 4xx, fix credentials/URL/payload for the specific provider; for 5xx, retry and check the provider's status.","For TLS errors, ensure CA chain is valid on the host or correct the target URL scheme."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const proxyEnv = process.env.notification_proxy || process.env.NOTIFICATION_PROXY;\nif (proxyEnv) {\n    try { new URL(proxyEnv); } catch { throw new Error(`Invalid NOTIFICATION_PROXY URL: ${proxyEnv}`); }\n}","typeGuard":"/** @param {unknown} e */\nfunction classifyAxiosError(e) {\n    if (!e) return \"unknown\";\n    if (e.response) return `http-${e.response.status}`;\n    if (e.code) return `transport-${e.code}`; // ECONNREFUSED, ENOTFOUND, ETIMEDOUT...\n    return \"other\";\n}","tryCatchPattern":"try {\n    await provider.send(notification, msg, monitorJSON, heartbeatJSON);\n} catch (e) {\n    // throwGeneralAxiosError already aggregated context; classify for action\n    if (/\\(code=ECONN(?:REFUSED|RESET)\\)/.test(e.message)) { /* network - retry */ }\n    if (/\\(HTTP 5\\d\\d\\)/.test(e.message)) { /* server error - retry */ }\n    if (/\\(HTTP 4\\d\\d\\)/.test(e.message)) { /* client/config error - do not retry */ }\n    throw e;\n}","preventionTips":["Parse the aggregated message: '(code=...)' = transport issue, '(HTTP <n>)' = server responded.","Validate NOTIFICATION_PROXY URL at app startup.","For 5xx/transport errors, retry with backoff; for 4xx, fix config."],"tags":["error-handling","axios","base-class","network","aggregation"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}