hcengineering/platform · error

Client ${clientId} not found

Error message

Client ${clientId} not found

What it means

BackRPC server's request() sends a back-channel RPC request to a connected client, but the given clientId has no mapping to an underlying transport identity. The server throws because it cannot route the request to an unknown client. This indicates the client was never connected, or has since disconnected and been removed from clientMapping.

Source

Thrown at foundations/net/packages/backrpc/src/server.ts:314

              const { message, stack } = parseJSON(payload.toString())
              req?.reject(new Error(message + '\n' + stack))
            } catch (err: any) {
              console.error(err)
            }
            this.backRequests.delete(reqID)
            break
          }
        }
      } catch (err: any) {
        console.error(err)
      }
    }
  }

  async request (clientId: ClientT, method: string, params: any): Promise<any> {
    const clientIdentity = this.clientMapping.get(clientId)
    if (clientIdentity === undefined) {
      throw new Error(`Client ${clientId} not found`)
    }
    return await new Promise<any>((resolve, reject) => {
      const reqId = clientId + '-' + this.requestCounter++
      this.backRequests.set(reqId, { resolve, reject })

      void this.doSend([clientIdentity, backrpcOperations.request, reqId, stringifyJSON([method, params])]).catch(
        (err) => {
          reject(err)
        }
      )
    })
  }

  async send (clientId: ClientT, body: any): Promise<any> {
    const clientIdentity = this.clientMapping.get(clientId)
    if (clientIdentity === undefined) {
      throw new Error(`Client ${clientId as string} not found`)
    }

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Verify the clientId exists before calling request by tracking registrations from the hello/handshake path
  2. Reconnect or re-handshake the client to obtain a fresh clientId and retry
  3. Handle the thrown error by removing the stale client reference from caller state
  4. Check for client disconnects between obtaining the clientId and issuing the request

Example fix

// before
await server.request(clientId, 'op', params) // throws if client gone
// after
if (server.hasClient(clientId)) { // track registration yourself if no such helper
  await server.request(clientId, 'op', params)
} else {
  await reconnectAndRetry(clientId)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// maintain your own registry of live clientIds
function isClientLive(clientId: string): boolean {
  return liveClients.has(clientId)
}

Type guard

function hasClient(mapping: Map<ClientT, unknown>, clientId: ClientT): clientId is ClientT {
  return mapping.has(clientId)
}

Try / catch

try {
  await server.request(clientId, method, params)
} catch (e) {
  if (e instanceof Error && e.message === `Client ${clientId} not found`) {
    dropStaleClient(clientId)
  } else { throw e }
}

Prevention

When it happens

Trigger: Calling server.request(clientId, method, params) with a clientId that was never registered via hello, or whose connection was closed and pruned from clientMapping before the call.

Common situations: Race after client disconnect: caller holds a stale clientId from an earlier session and sends a request; load-balanced setup where the request lands on a server instance the client never connected to; client restart produced a new UUID.

Related errors


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