hcengineering/platform · error · PlatformError

ConnectionClosed

Error message

ConnectionClosed

What it means

sendRequest throws a PlatformError with status ConnectionClosed when a request is attempted on a client connection that has already been closed. The library guards the request path so callers never wait on a socket that will never answer. Any RPC (including pings and model loads) issued after close fails immediately with this error.

Source

Thrown at plugins/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 client/connection closed state before issuing requests and re-create the connection if closed
  2. Wrap request calls in retry logic that reopens the connection on ConnectionClosed
  3. Avoid closing the connection while async operations are still pending; await them first
  4. Reconnect and re-authenticate on this error, since the old connection cannot be reused

Example fix

// before
const model = await client.loadModel()
// after
if (connection.closed) await reconnect()
const model = await client.loadModel()
Defensive patterns

Strategy: retry

Validate before calling

if (connection.closed) { await reconnect(connection) }

Type guard

function isConnectionClosed(err: unknown): boolean {
  return err instanceof PlatformError && err.status.status === platform.status.ConnectionClosed
}

Try / catch

try {
  await client.loadModel()
} catch (err) {
  if (isConnectionClosed(err)) {
    await reconnect(connection)
    return client.loadModel()
  }
  throw err
}

Prevention

When it happens

Trigger: Calling any client API (loadModel, getAccount, schedulePing, handleMsg-triggered requests, checkArrayBufferPing) after connection.close() was invoked or this.closed was set true; racing a close() against in-flight operations.

Common situations: App shutdown or page unload closing the connection while background requests are pending; reconnect logic issuing requests on a stale closed client instance; timeout handlers closing the connection while a loadModel/getAccount call is in flight.

Related errors


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