{"record":{"id":"aa8c885accfaec5a","repo":"louislam/uptime-kuma","slug":"expected-tls-alert-expectedtlsalert-but-got-u","errorCode":null,"errorMessage":"Expected TLS alert '${expectedTlsAlert}' but got unexpected error: ${result.errorMessage}","messagePattern":"Expected TLS alert '(.+?)' but got unexpected error: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/monitor-types/tcp.js","lineNumber":333,"sourceCode":"            await monitor.handleTlsInfo(result.tlsInfo);\n        }\n\n        // Check if we got the expected alert\n        // Note: Error messages below could be translated, but alert names (e.g., certificate_required)\n        // are from RFC 8446 spec and should remain in English for consistency with the spec.\n        if (result.alertName === expectedTlsAlert) {\n            heartbeat.status = UP;\n            heartbeat.msg = `TLS alert received as expected: ${result.alertName} (${result.alertNumber})`;\n        } else if (result.success) {\n            throw new Error(\n                `Expected TLS alert '${expectedTlsAlert}' but connection succeeded. The server accepted the connection without requiring a client certificate.`\n            );\n        } else if (result.alertNumber !== null) {\n            throw new Error(\n                `Expected TLS alert '${expectedTlsAlert}' but received '${result.alertName}' (${result.alertNumber})`\n            );\n        } else {\n            throw new Error(\n                `Expected TLS alert '${expectedTlsAlert}' but got unexpected error: ${result.errorMessage}`\n            );\n        }\n    }\n\n    /**\n     * Attempt TLS connection and capture result/alert\n     * @param {object} monitor Monitor object\n     * @param {object} options TLS connection options\n     * @param {number} startTime Connection start timestamp\n     * @param {number} timeout Connection timeout in ms\n     * @returns {Promise<object>} Connection result with success, responseTime, tlsInfo, alertNumber, alertName, errorMessage\n     */\n    attemptTlsConnection(monitor, options, startTime, timeout) {\n        return new Promise((resolve, reject) => {\n            const socket = tls.connect(options);\n\n            const timeoutId = setTimeout(() => {","sourceCodeStart":315,"sourceCodeEnd":351,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/monitor-types/tcp.js#L315-L351","documentation":"Final else branch of checkTlsAlert (tcp.js:332-335). attemptTlsConnection returned success:false but parseTlsAlertNumber could not extract a numeric alert (alertNumber === null), so the failure is not a recognizable TLS alert — it is a transport/parse-level error surfaced verbatim in result.errorMessage.","triggerScenarios":"Connection reset before any TLS byte (firewall RST), DNS failure surfaced through tls.connect's error event, ECONNREFUSED, or an error string format Node changed so the regex in parseTlsAlertNumber no longer extracts the number.","commonSituations":"Host down or port closed; intermediate proxy does not speak TLS on that port; Node.js version upgrade altered the error message format, breaking the alert-number parser.","solutions":["Inspect result.errorMessage in the heartbeat for the true cause (e.g. ECONNREFUSED, getaddrinfo ENOTFOUND).","Confirm host/port reachability with `nc -vz host port` or `openssl s_client`.","If the error looks like a TLS alert but no number was parsed, check whether a newer Node version changed the message shape and report/patch parseTlsAlertNumber."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-flight DNS + TCP so transport errors surface as transport, not as alert-check failures\nconst dns = require('dns').promises;\nconst net = require('net');\nasync function endpointReady(host, port) {\n    await dns.lookup(host); // throws on DNS failure\n    return new Promise((res) => {\n        const s = net.createConnection({ host, port });\n        s.setTimeout(5000);\n        s.on('connect', () => { s.destroy(); res(true); });\n        s.on('error', () => res(false));\n        s.on('timeout', () => { s.destroy(); res(false); });\n    });\n}","typeGuard":"function isAttemptResult(v) {\n    return v != null && typeof v === 'object'\n        && typeof v.success === 'boolean'\n        && (v.alertNumber === null || typeof v.alertNumber === 'number')\n        && (typeof v.errorMessage === 'string' || v.errorMessage == null);\n}","tryCatchPattern":"try {\n    await monitor.checkTlsAlert(monitor, heartbeat, expectedTlsAlert);\n} catch (e) {\n    if (/got unexpected error/.test(e.message)) {\n        const inner = e.message.split('error:')[1]?.trim();\n        heartbeat.msg = `Transport-level TLS failure (no alert): ${inner}`;\n    }\n}","preventionTips":["Separate transport reachability from TLS-alert semantics in your alerts.","Log parseTlsAlertNumber hits/misses so a parser regression is visible."],"tags":["tls","mtls","tcp-monitor","network","transport"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}