louislam/uptime-kuma · warning · Error
Unknown Websocket Error
Error message
Unknown Websocket Error
What it means
Defensive fallback at websocket-upgrade.js:50. Fires only if attemptUpgrade returns neither a close code NOR a message — a state the code comment marks 'should never happen'. It guards against a future regression where attemptUpgrade resolves with [undefined, undefined].
Source
Thrown at server/monitor-types/websocket-upgrade.js:50
const [message, code] = await this.attemptUpgrade(monitor);
if (typeof code !== "undefined") {
// If returned status code matches user controlled accepted status code(default 1000), return success
if (checkStatusCode(code, JSON.parse(monitor.accepted_statuscodes_json))) {
heartbeat.status = UP;
heartbeat.msg = message;
return; // success at this point
}
// Throw an error using friendly name if defined, fallback to generic msg
throw new Error(WS_ERR_CODE[code] || `Unexpected status code: ${code}`);
}
// If no close code, then an error has occurred, display to user
if (typeof message !== "undefined") {
throw new Error(`${message}`);
}
// Throw generic error if nothing is defined, should never happen
throw new Error("Unknown Websocket Error");
}
/**
* Builds the WebSocket options object for authentication and TLS.
* Supports basic auth, OAuth2 client credentials, and mTLS.
* @param {object} monitor The monitor object for input parameters.
* @returns {Promise<object>} The options object to pass to the WebSocket constructor.
*/
async buildWsOptions(monitor) {
const options = {};
const timeoutMs = (monitor.timeout ?? 20) * 1000;
options.handshakeTimeout = timeoutMs;
// Parse custom headers if provided
if (monitor.headers) {
try {
options.headers = JSON.parse(monitor.headers);View on GitHub (pinned to 6b5ea01557)
Solutions
- This indicates a code/library bug, not a config issue — inspect attemptUpgrade's promise resolution paths.
- Upgrade or pin the `ws` dependency to a version tested against this monitor.
- Add logging in attemptUpgrade's error/close handlers to capture which event fired with what payload.
Defensive patterns
Strategy: try-catch
Validate before calling
// Defensive: assert attemptUpgrade never returns [undefined, undefined] before throwing the generic error
const [msg, code] = await this.attemptUpgrade(monitor);
if (msg == null && code == null) {
log.error('attemptUpgrade returned empty result — ws handler regression suspected');
} Type guard
function hasWsSignal([msg, code]) { return msg != null || code != null; } Try / catch
try {
await monitor.check(monitor, heartbeat, server);
} catch (e) {
if (e.message === 'Unknown Websocket Error') {
log.error('ws monitor produced no signal — report upstream; ws lib version:', require('ws/package.json').version);
}
} Prevention
- Pin the ws library version and re-test on upgrades.
- Add a regression test asserting attemptUpgrade always yields at least one signal.
When it happens
Trigger: Programmatic: attemptUpgrade was modified to swallow the error event and resolve empty; a ws library version change altered event semantics so neither 'close' nor 'error' produced values; a mocked/stubbed monitor returned nothing.
Common situations: Custom fork of the monitor type that broke the promise resolution; ws library major-version upgrade that changed when 'error' vs 'close' fire.
Related errors
- ${WS_ERR_CODE[code] || `Unexpected status code: ${code}`}
- domain_expiry_unsupported_monitor_type
- domain_expiry_unsupported_missing_target
- The oauth config is invalid. ${e.message}
- Service Name is required.
AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12).
Data as JSON: /api/errors/15d1268e627978ed.
Report an issue: GitHub.