{"record":{"id":"fbaa926cab4de962","repo":"louislam/uptime-kuma","slug":"message","errorCode":null,"errorMessage":"${message}","messagePattern":"\\$\\{message\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/monitor-types/websocket-upgrade.js","lineNumber":47,"sourceCode":"     * @inheritdoc\n     */\n    async check(monitor, heartbeat, _server) {\n        const [message, code] = await this.attemptUpgrade(monitor);\n\n        if (typeof code !== \"undefined\") {\n            // If returned status code matches user controlled accepted status code(default 1000), return success\n            if (checkStatusCode(code, JSON.parse(monitor.accepted_statuscodes_json))) {\n                heartbeat.status = UP;\n                heartbeat.msg = message;\n                return; // success at this point\n            }\n\n            // Throw an error using friendly name if defined, fallback to generic msg\n            throw new Error(WS_ERR_CODE[code] || `Unexpected status code: ${code}`);\n        }\n        // If no close code, then an error has occurred, display to user\n        if (typeof message !== \"undefined\") {\n            throw new Error(`${message}`);\n        }\n        // Throw generic error if nothing is defined, should never happen\n        throw new Error(\"Unknown Websocket Error\");\n    }\n\n    /**\n     * Builds the WebSocket options object for authentication and TLS.\n     * Supports basic auth, OAuth2 client credentials, and mTLS.\n     * @param {object} monitor The monitor object for input parameters.\n     * @returns {Promise<object>} The options object to pass to the WebSocket constructor.\n     */\n    async buildWsOptions(monitor) {\n        const options = {};\n\n        const timeoutMs = (monitor.timeout ?? 20) * 1000;\n        options.handshakeTimeout = timeoutMs;\n\n        // Parse custom headers if provided","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/monitor-types/websocket-upgrade.js#L29-L65","documentation":"websocket-upgrade.js:46-47. attemptUpgrade returned a message but NO close code (code === undefined), meaning the connection never got far enough to negotiate a normal close — only an error event with a textual reason. The raw message is re-thrown verbatim.","triggerScenarios":"TLS handshake failure on wss://, DNS resolution error, ECONNREFUSED, invalid WebSocket URL scheme, or an upgrade rejection that surfaces as an 'error' event with a message but no close frame.","commonSituations":"Wrong URL scheme (ws:// against a TLS-only port), expired/invalid server cert, network egress blocked, ws library emitting 'Unexpected server response: 401' when auth headers are wrong.","solutions":["Read the message verbatim — it usually names the real cause (e.g. 'Unexpected server response: 401', 'self signed certificate').","Verify the URL scheme matches the endpoint (wss:// for TLS).","For auth-related messages, check basic/bearer/oauth credentials in buildWsOptions output.","For TLS messages, set ignoreTls or supply the correct CA."],"exampleFix":"// before: ws://endpoint requiring TLS → 'Unexpected server response'\n// after: use the TLS endpoint\nmonitor.url = monitor.url.replace(/^ws:/, 'wss:');","handlingStrategy":"try-catch","validationCode":"// Validate URL scheme/auth before attempting the upgrade\nfunction validateWsTarget(url) {\n    const u = new URL(url);\n    if (!/^wss?:$/.test(u.protocol)) throw new Error(`Bad scheme: ${u.protocol}`);\n    return u;\n}","typeGuard":"function isWsUpgradeResult(v) {\n    return Array.isArray(v) && v.length === 2\n        && (typeof v[0] === 'string' || v[0] == null)\n        && (typeof v[1] === 'number' || v[1] == null);\n}","tryCatchPattern":"try {\n    await monitor.check(monitor, heartbeat, server);\n} catch (e) {\n    if (/Unexpected server response: (401|403)/.test(e.message)) {\n        heartbeat.msg = `WS auth rejected: ${e.message}`;\n    } else if (/certificate|self-signed/i.test(e.message)) {\n        heartbeat.msg = `WS TLS problem: ${e.message}`;\n    }\n    heartbeat.status = DOWN;\n}","preventionTips":["Use wss:// for TLS endpoints and pre-validate credentials.","Keep ignoreTls/CA configuration in sync with the equivalent HTTP monitor."],"tags":["websocket","network","tls","auth"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}