{"record":{"id":"876357aac4d028a0","repo":"hcengineering/platform","slug":"platform-status-connectionclosed","errorCode":"platform.status.ConnectionClosed","errorMessage":"ConnectionClosed","messagePattern":"ConnectionClosed","errorType":"error_code","errorClass":"PlatformError","httpStatus":null,"severity":"error","filePath":"foundations/core/packages/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/foundations/core/packages/client-resources/src/connection.ts#L667-L703","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\nconst result = await conn.sendRequest(method, params)\n// after\nimport { PlatformError, platform } from '@hcengineering/client-resources'\ntry {\n  const result = await conn.sendRequest(method, params)\n} catch (err) {\n  if (err instanceof PlatformError && err.status.status === platform.status.ConnectionClosed) {\n    await reconnect(); return sendWithRetry(method, params)\n  }\n  throw err\n}","handlingStrategy":"try-catch","validationCode":"if (conn.closed) {\n  await conn.openConnection() // re-establish before sending\n}","typeGuard":"function isConnectionClosed(err: unknown): boolean {\n  return err instanceof PlatformError && err.status.status === platform.status.ConnectionClosed\n}","tryCatchPattern":"try {\n  return await conn.sendRequest(method, params)\n} catch (err) {\n  if (isConnectionClosed(err)) {\n    await conn.openConnection()\n    return conn.sendRequest(method, params) // single retry after reconnect\n  }\n  throw err\n}","preventionTips":["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"],"tags":["websocket","connection","rpc"],"backgroundTag":"connection-closed","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}