perspective-dev/perspective · error · Error
WebSocket transport error
Error message
WebSocket transport error (${ws.readyState}) What it means
The perspective WebSocket client throws this when `send_message` is called while the underlying WebSocket is in the CLOSING (2) or CLOSED (3) readyState — the message cannot be transported. The error is first reported to the client via `client.handle_error` (which may trigger a reconnect) and then thrown to the caller.
Solutions
- Check `client.is_connected()` / the WebSocket readyState before sending, and skip or queue messages when not open.
- Await connection before sending: wrap sends in the client's connect/open promise (e.g. `await client.connect()` or the socket's `open` event).
- Add a retry wrapper that listens for the reconnection attempt triggered by handle_error and resends queued messages once readyState is OPEN.
- Verify the server/proxy keepalive configuration (timeouts, ping intervals) if closures happen during idle periods.
Example fix
// before
const client = await websocket("ws://host/perspective");
setInterval(() => client.send_message(makeRequest()), 1000); // throws after socket closes
// after
const client = await websocket("ws://host/perspective");
async function safeSend(req) {
if (client.ws.readyState !== WebSocket.OPEN) {
await reconnectAndWait(client);
}
try {
client.send_message(req);
} catch (e) {
if (String(e.message).startsWith("WebSocket transport error")) {
await reconnectAndWait(client);
client.send_message(req);
} else throw e;
}
} Defensive patterns
Strategy: try-catch
Validate before calling
function canSend(client) {
return client.ws && client.ws.readyState === WebSocket.OPEN;
}
if (!canSend(client)) await reconnectAndWait(client); Type guard
function isSocketOpen(ws: WebSocket | undefined): ws is WebSocket & { readyState: typeof WebSocket.OPEN } {
return !!ws && ws.readyState === WebSocket.OPEN;
} Try / catch
try {
client.send_message(msg);
} catch (e) {
if (/^WebSocket transport error \((2|3)\)/.test(e.message)) {
await reconnect(client);
client.send_message(msg); // resend after reconnect
} else throw e;
} Prevention
- Always await the connection/open promise before sending.
- Subscribe to the socket's `close` event to pause senders and resume after reconnect.
- Implement a message queue that buffers sends while the socket is not OPEN.
- Configure server/proxy keepalive pings to avoid idle closes mid-session.
When it happens
Trigger: Calling `client.send_message(...)` (or any higher-level API that sends, e.g. table/view requests) after the WebSocket has closed — server shutdown, network drop, explicit `close()`, or idle/keepalive failure — before the reconnect completes.
Common situations: Server restart or proxy timeout closing the socket while the app continues issuing queries; calling send during a reconnect window; forgetting to await an initial connection promise; firing requests after `client.close()` was called.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
AI-assisted analysis of perspective-dev/perspective@11c8238c0c (2026-09-09).
Data as JSON: /api/errors/64ae4fd551de8346.
Report an issue: GitHub.
Appendix: source
Thrown at rust/perspective-js/src/ts/websocket.ts:77
client.handle_error(msg, connect);
reject(msg);
};
ws.onmessage = (event) => {
client.handle_response(event.data);
};
await receiver;
}
async function send_message(proto: Uint8Array) {
if (
ws.readyState === WebSocket.CLOSING ||
ws.readyState === WebSocket.CLOSED
) {
const msg = `WebSocket transport error (${ws.readyState})`;
client.handle_error(msg, connect);
throw new Error(msg);
} else if (ws.readyState === WebSocket.CONNECTING) {
const msg = `WebSocket message dropped (${ws.readyState})`;
throw new Error(msg);
} else {
const buffer = proto.slice().buffer;
ws.send(buffer);
}
}
async function on_close() {
console.debug("Closing WebSocket");
ws.close();
}
client = new Client(send_message, on_close);
await connect();
return client;
}View on GitHub (pinned to 11c8238c0c)