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

  1. Check connection state (isClosed/closed) before sending, or guard with a connected flag.
  2. Reopen the connection (openConnection) before retrying the request.
  3. Cancel or drain pending tasks (pings, loads) on close to avoid post-close sends.
  4. Catch PlatformError and inspect status === platform.status.ConnectionClosed to trigger reconnection instead of crashing.
  5. 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

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


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/876357aac4d028a0. Report an issue: GitHub.