louislam/uptime-kuma · error · Error
TLS Connection failed: ${message}
Error message
TLS Connection failed: ${message} What it means
Wraps every failure path inside checkTlsCertificate (tcp.js:236-279). The outer try/catch re-throws any underlying error — TLS handshake error, the 'Connection timed out' from socket.setTimeout (line 263), a checkCertificate failure, or the explicit 'Certificate is invalid' (line 269) — prefixed with 'TLS Connection failed: '. It exists so the monitor heartbeat surfaces one consistent error family regardless of which sub-step broke.
Source
Thrown at server/monitor-types/tcp.js:273
}
});
socket.on("error", (error) => {
reject(error);
});
socket.setTimeout(1000 * TIMEOUT, () => {
reject(new Error("Connection timed out"));
});
});
await monitor.handleTlsInfo(tlsInfoObject);
if (!tlsInfoObject.valid) {
throw new Error("Certificate is invalid");
}
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown error";
throw new Error(`TLS Connection failed: ${message}`);
} finally {
if (socket && !socket.destroyed) {
socket.end();
}
}
}
/**
* Check for expected TLS alert (for mTLS verification)
* @param {object} monitor Monitor object
* @param {object} heartbeat Heartbeat object
* @param {string} expectedTlsAlert Expected TLS alert name
* @returns {Promise<void>}
*/
async checkTlsAlert(monitor, heartbeat, expectedTlsAlert) {
const timeout = monitor.timeout * 1000 || 30000;
const startTime = Date.now();
View on GitHub (pinned to 6b5ea01557)
Solutions
- Read the inner ${message} first — it pinpoints which sub-step failed (timeout vs invalid cert vs handshake error).
- If the message is 'Certificate is invalid' or names a cert problem, open the host in a browser or `openssl s_client -connect host:port -servername host` to inspect the chain/expiry.
- If the message is 'Connection timed out', verify network reachability and that monitor.hostname/port are correct.
- For self-signed/internal CAs, set the monitor's ignore-TLS option or supply the CA via the monitor's tls_ca field instead of disabling validation.
- Increase monitor.timeout if the host legitimately needs longer than TIMEOUT seconds to complete the handshake.
Example fix
// before: monitor points at host with self-signed cert and rejectUnauthorized on
// after: configure the monitor to trust the internal CA
monitor.tls_ca = fs.readFileSync('/etc/ssl/internal-ca.pem');
monitor.ignoreTls = false; Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight reachability + cert sanity before relying on checkTlsCertificate
const net = require('net');
function hostReachable(host, port, ms = 5000) {
return new Promise((res) => {
const s = net.createConnection({ host, port });
s.setTimeout(ms);
s.on('connect', () => { s.destroy(); res(true); });
s.on('error', () => res(false));
s.on('timeout', () => { s.destroy(); res(false); });
});
}
if (!(await hostReachable(monitor.hostname, monitor.port))) {
throw new Error(`Host unreachable: ${monitor.hostname}:${monitor.port}`);
} Type guard
function isTlsInfoObject(v) {
return v != null && typeof v === 'object'
&& typeof v.valid === 'boolean'
&& 'certInfo' in v;
} Try / catch
try {
await monitor.checkTlsCertificate(monitor);
} catch (e) {
// unwrap: 'TLS Connection failed: <reason>'
const reason = e.message.startsWith('TLS Connection failed:') ? e.message.slice('TLS Connection failed:'.length).trim() : e.message;
heartbeat.status = reason.includes('timed out') ? PENDING : DOWN;
heartbeat.msg = reason;
} Prevention
- Whitelist internal CAs via monitor.tls_ca instead of disabling verification globally.
- Keep monitor.timeout comfortably above the slowest expected TLS handshake for the target.
- Run a TCP pre-flight before TLS to separate reachability from cert problems.
When it happens
Trigger: Calling tls.connect against an unreachable/filtered host (timeout fires), a server whose certificate is self-signed/expired/chain-incomplete when rejectUnauthorized is on, a hostname mismatch (SNI vs cert CN/SAN), or a STARTTLS negotiation that the server refuses.
Common situations: Monitoring an internal service behind a self-signed cert without toggling 'ignore TLS', a renewed cert whose intermediate chain was not bundled, a hostname recently changed in DNS but the monitor still points at the old one, firewall egress blocking the TLS port so the 1.5xTIMEOUT socket timer fires.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Expected TLS alert '${expectedTlsAlert}' but connection succ
- Expected TLS alert '${expectedTlsAlert}' but received '${res
- Expected TLS alert '${expectedTlsAlert}' but got unexpected
- Connection to Docker daemon timed out.
- TLS certificate is not authorized: ${tlsInfo.error}
AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12).
Data as JSON: /api/errors/dd901e54f6d984b2.
Report an issue: GitHub.