{"record":{"id":"da1bcab0aa3cab1c","repo":"hcengineering/platform","slug":"client-clientid-as-string-not-found","errorCode":null,"errorMessage":"Client ${clientId as string} not found","messagePattern":"Client (.+?) not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"foundations/net/packages/backrpc/src/server.ts","lineNumber":331,"sourceCode":"    if (clientIdentity === undefined) {\n      throw new Error(`Client ${clientId} not found`)\n    }\n    return await new Promise<any>((resolve, reject) => {\n      const reqId = clientId + '-' + this.requestCounter++\n      this.backRequests.set(reqId, { resolve, reject })\n\n      void this.doSend([clientIdentity, backrpcOperations.request, reqId, stringifyJSON([method, params])]).catch(\n        (err) => {\n          reject(err)\n        }\n      )\n    })\n  }\n\n  async send (clientId: ClientT, body: any): Promise<any> {\n    const clientIdentity = this.clientMapping.get(clientId)\n    if (clientIdentity === undefined) {\n      throw new Error(`Client ${clientId as string} not found`)\n    }\n    await this.doSend([clientIdentity, backrpcOperations.event, '', stringifyJSON(body)])\n  }\n\n  async close (): Promise<void> {\n    this.closed = true\n    this.stopTick?.()\n    this.router.close()\n  }\n}\n","sourceCodeStart":313,"sourceCodeEnd":342,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/net/packages/backrpc/src/server.ts#L313-L342","documentation":"BackRPC server's send() pushes a one-way event to a connected client, but clientId has no entry in clientMapping, so no transport identity exists to deliver to. It throws instead of silently dropping the event. Same root cause as request(): unknown or disconnected client.","triggerScenarios":"Calling server.send(clientId, body) for a clientId that never connected, already disconnected, or connected to a different server instance.","commonSituations":"Broadcast loops that iterate a cached client list without pruning disconnected ids; sending a final event after the client's close completed; restarting the server while clients reconnect with new ids.","solutions":["Prune stale clientIds from your registry on disconnect events before sending","Re-establish the client connection and resend the event","Wrap sends in try-catch and treat unknown-client as a disconnect signal","Confirm the client connected to the same server instance handling the send"],"exampleFix":"// before\nawait server.send(clientId, { type: 'notify' })\n// after\ntry {\n  await server.send(clientId, { type: 'notify' })\n} catch (e) {\n  removeClient(clientId) // stale; drop or reconnect\n}","handlingStrategy":"try-catch","validationCode":"// skip sends for clients no longer tracked\nif (!liveClients.has(clientId)) return","typeGuard":"function canSend(mapping: Map<ClientT, unknown>, clientId: ClientT): boolean {\n  return mapping.get(clientId) !== undefined\n}","tryCatchPattern":"try {\n  await server.send(clientId, body)\n} catch (e) {\n  if (e instanceof Error && e.message.includes('not found')) {\n    removeClient(clientId)\n  } else { throw e }\n}","preventionTips":["Prune client lists on disconnect","Avoid post-close final event sends","Treat unknown-client as disconnect signal in broadcast loops","Ping clients before relying on stale ids"],"tags":["rpc","backrpc","unknown-client","event-delivery"],"backgroundTag":"rpc-client-not-found","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}