hcengineering/platform · error · PlatformError
platform.status.ConnectionClosed
platform.status.ConnectionClosed
Error message
ConnectionClosed
What it means
sendRequest on the client-resources connection throws a PlatformError with status ConnectionClosed when the connection has already been closed. It prevents sending requests over a dead WebSocket/RPC channel. Raised IN sendRequest, which is used by schedulePing, handleMsg, openConnection, loadModel, and getAccount.
Source
Thrown at foundations/core/packages/client-resources/src/connection.ts:685
}
private sendRequest (data: {
method: string
params: any[]
// If not defined, on reconnect with timeout, will retry automatically.
retry?: () => Promise<boolean>
handleResult?: (result: any) => Promise<void>
once?: boolean // Require handleResult to retrieve result
measure?: (time: number, result: any, serverTime: number, queue: number, toRecieve: number) => void
allowReconnect?: boolean
overrideId?: number
}): Promise<any> {
return this.ctx.with(
'send-request',
{},
async (ctx) => {
if (this.closed) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.ConnectionClosed, {}))
}
if (this.slowDownTimer > 0) {
// We need to wait a bit to avoid ban.
await new Promise((resolve) => setTimeout(resolve, this.slowDownTimer))
}
if (data.once === true) {
// Check if has same request already then skip
const dparams = JSON.stringify(data.params)
for (const [, v] of this.requests) {
if (v.method === data.method && JSON.stringify(v.params) === dparams) {
// We have same unanswered, do not add one more.
return
}
}
}
View on GitHub (pinned to 63e28dc964)
Solutions
- Check connection state (isClosed/closed) before sending, or guard with a connected flag.
- Reopen the connection (openConnection) before retrying the request.
- Cancel or drain pending tasks (pings, loads) on close to avoid post-close sends.
- Catch PlatformError and inspect status === platform.status.ConnectionClosed to trigger reconnection instead of crashing.
- Ensure reconnect backoff completes before issuing new requests (respect slowDownTimer).
Example fix
// before
const result = await conn.sendRequest(method, params)
// after
import { PlatformError, platform } from '@hcengineering/client-resources'
try {
const result = await conn.sendRequest(method, params)
} catch (err) {
if (err instanceof PlatformError && err.status.status === platform.status.ConnectionClosed) {
await reconnect(); return sendWithRetry(method, params)
}
throw err
} Defensive patterns
Strategy: try-catch
Validate before calling
if (conn.closed) {
await conn.openConnection() // re-establish before sending
} Type guard
function isConnectionClosed(err: unknown): boolean {
return err instanceof PlatformError && err.status.status === platform.status.ConnectionClosed
} Try / catch
try {
return await conn.sendRequest(method, params)
} catch (err) {
if (isConnectionClosed(err)) {
await conn.openConnection()
return conn.sendRequest(method, params) // single retry after reconnect
}
throw err
} Prevention
- Track connection state and skip sends after close()
- Cancel pings/loads on unmount or shutdown to avoid post-close sends
- Implement a reconnect wrapper around sendRequest
- Respect slowDownTimer backoff before retrying
When it happens
Trigger: Any RPC attempted after connection.close() or after the connection dropped and was marked closed; queued pings or model loads firing after shutdown; race between close and in-flight openConnection/loadModel/getAccount calls.
Common situations: App shutdown or navigation away while async tasks still send requests; server restarted and client marked the connection closed; component unmounted while a load is pending; reconnect logic not yet completed before the next request.
Related errors
- ${reply.error}
- FORCE CLOSE
- The "ws" package is required for NodeWebSocketFactory.
- HTTP error ${res.status}
- result.error
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/876357aac4d028a0.
Report an issue: GitHub.