{"record":{"id":"969d8f9f4a4531a0","repo":"hcengineering/platform","slug":"connectionclosed","errorCode":null,"errorMessage":"ConnectionClosed","messagePattern":"ConnectionClosed","errorType":"error_code","errorClass":"PlatformError","httpStatus":null,"severity":"error","filePath":"plugins/client-resources/src/connection.ts","lineNumber":685,"sourceCode":"  }\n\n  private sendRequest (data: {\n    method: string\n    params: any[]\n    // If not defined, on reconnect with timeout, will retry automatically.\n    retry?: () => Promise<boolean>\n    handleResult?: (result: any) => Promise<void>\n    once?: boolean // Require handleResult to retrieve result\n    measure?: (time: number, result: any, serverTime: number, queue: number, toRecieve: number) => void\n    allowReconnect?: boolean\n    overrideId?: number\n  }): Promise<any> {\n    return this.ctx.with(\n      'send-request',\n      {},\n      async (ctx) => {\n        if (this.closed) {\n          throw new PlatformError(new Status(Severity.ERROR, platform.status.ConnectionClosed, {}))\n        }\n\n        if (this.slowDownTimer > 0) {\n          // We need to wait a bit to avoid ban.\n          await new Promise((resolve) => setTimeout(resolve, this.slowDownTimer))\n        }\n\n        if (data.once === true) {\n          // Check if has same request already then skip\n          const dparams = JSON.stringify(data.params)\n          for (const [, v] of this.requests) {\n            if (v.method === data.method && JSON.stringify(v.params) === dparams) {\n              // We have same unanswered, do not add one more.\n              return\n            }\n          }\n        }\n","sourceCodeStart":667,"sourceCodeEnd":703,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/plugins/client-resources/src/connection.ts#L667-L703","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check client/connection closed state before issuing requests and re-create the connection if closed","Wrap request calls in retry logic that reopens the connection on ConnectionClosed","Avoid closing the connection while async operations are still pending; await them first","Reconnect and re-authenticate on this error, since the old connection cannot be reused"],"exampleFix":"// before\nconst model = await client.loadModel()\n// after\nif (connection.closed) await reconnect()\nconst model = await client.loadModel()","handlingStrategy":"retry","validationCode":"if (connection.closed) { await reconnect(connection) }","typeGuard":"function isConnectionClosed(err: unknown): boolean {\n  return err instanceof PlatformError && err.status.status === platform.status.ConnectionClosed\n}","tryCatchPattern":"try {\n  await client.loadModel()\n} catch (err) {\n  if (isConnectionClosed(err)) {\n    await reconnect(connection)\n    return client.loadModel()\n  }\n  throw err\n}","preventionTips":["Check this.closed / connection state before issuing requests","Serialize close() so it never runs while requests are pending","Implement automatic reconnect-and-retry on ConnectionClosed","Watch connection lifecycle events to invalidate queued operations early"],"tags":["connection","network","lifecycle"],"backgroundTag":"connection-closed","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}