{"record":{"id":"4ba64da53130be2d","repo":"louislam/uptime-kuma","slug":"ws-err-code-code-unexpected-status-code","errorCode":null,"errorMessage":"${WS_ERR_CODE[code] || `Unexpected status code: ${code}`}","messagePattern":"\\$\\{WS_ERR_CODE\\[code\\] \\|\\| `Unexpected status code: \\$\\{code\\}`\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/monitor-types/websocket-upgrade.js","lineNumber":43,"sourceCode":"class WebSocketMonitorType extends MonitorType {\n    name = \"websocket-upgrade\";\n\n    /**\n     * @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","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/louislam/uptime-kuma/blob/6b5ea0155793e666666745fb8d6fef1e829543a2/server/monitor-types/websocket-upgrade.js#L25-L61","documentation":"In WebSocketMonitorType.check (websocket-upgrade.js:31-51). attemptUpgrade returned a close code, but it is neither in the user's accepted_statuscodes_json list nor in the built-in WS_ERR_CODE map (codes 1002-1015, 3000/3003/3008). The thrown message is the friendly name when known, else 'Unexpected status code: <code>'.","triggerScenarios":"Server closes with 1006 (abnormal closure / TCP drop), 1011 (internal server error), an application-level 4xxx code not whitelisted, or a 1000/1001 normal close that the user forgot to add to accepted_statuscodes_json.","commonSituations":"Default accepted codes do not match what the gateway returns; upstream reverse proxy (nginx/cloudflare) closes idle WebSockets with 1006; auth failure surfaces as a 3xxx code that is not whitelisted.","solutions":["Add the observed code to the monitor's Accepted Status Codes list (accepted_statuscodes_json).","If the code is 1006, investigate network/proxy interruption rather than adjusting accepted codes.","Verify the WebSocket URL, subprotocol, and auth headers are correct so the server does not close with 1011/3xxx.","Confirm reverse-proxy WebSocket upgrade support (e.g. nginx `proxy_set_header Upgrade $http_upgrade`)."],"exampleFix":"// before: accepted_statuscodes_json = [1000]\n// server legitimately closes with 1001 (Going Away) during deploys\n// after: accepted_statuscodes_json = [1000, 1001]","handlingStrategy":"validation","validationCode":"// Confirm the close code the server is likely to send is whitelisted\nconst WS_ERR_CODE = { 1000:'Normal', 1001:'Going Away', 1002:'Protocol error', 1011:'Internal Error', 1015:'TLS Handshake' /* ... */ };\nfunction ensureCodeAccepted(code, acceptedJson) {\n    const accepted = new Set(JSON.parse(acceptedJson || '[]'));\n    if (!accepted.has(code)) {\n        throw new Error(`WS close code ${code} (${WS_ERR_CODE[code]||'unknown'}) is not in accepted_statuscodes`);\n    }\n}","typeGuard":"function isWsCloseCode(v) { return typeof v === 'number' && v >= 1000 && v <= 4999; }","tryCatchPattern":"try {\n    await monitor.check(monitor, heartbeat, server);\n} catch (e) {\n    // 1006 = abnormal closure — treat as network, not app-level, failure\n    heartbeat.status = /Abnormal Closure|1006/.test(e.message) ? PENDING : DOWN;\n    heartbeat.msg = e.message;\n}","preventionTips":["Mirror your reverse-proxy/expected close codes into accepted_statuscodes_json.","Investigate recurring 1006 separately — it is almost always network, not config."],"tags":["websocket","status-code","network","monitor"],"backgroundTag":null,"analyzedSha":"6b5ea0155793e666666745fb8d6fef1e829543a2","analyzedAt":"2026-08-12T23:42:12.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}