{"record":{"id":"e3b0a93d6874c033","repo":"hcengineering/platform","slug":"response-statustext","errorCode":null,"errorMessage":"response.statusText","messagePattern":"response\\.statusText","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"foundations/communication/packages/rest-client/src/rest.ts","lineNumber":108,"sourceCode":"      modifiedBy,\n      modifiedOn: Date.now()\n    }\n  }\n\n  private async find<T>(operation: string, params: Record<string, any>): Promise<T[]> {\n    const searchParams = new URLSearchParams()\n    if (Object.keys(params).length > 0) {\n      searchParams.append('params', JSON.stringify(params))\n    }\n    const requestUrl = concatLink(\n      this.endpoint,\n      `/api/v1/request/communication/${operation}/${this.workspace}?${searchParams.toString()}`\n    )\n    return await retry(\n      async () => {\n        const response = await fetch(requestUrl, this.requestInit())\n        if (!response.ok) {\n          throw new Error(response.statusText)\n        }\n        return await extractJson<T[]>(response)\n      },\n      { retries }\n    )\n  }\n\n  async event (event: Event, socialId: SocialID): Promise<EventResult> {\n    const response = await fetch(concatLink(this.endpoint, `/api/v1/tx/${this.workspace}`), {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        Authorization: 'Bearer ' + this.token\n      },\n      keepalive: true,\n      body: JSON.stringify(this.wrapEvent(event, socialId))\n    })\n    if (!response.ok) {","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/communication/packages/rest-client/src/rest.ts#L90-L126","documentation":"The rest-client's generic `find` method GETs a communication API endpoint and, when `response.ok` is false, throws an Error whose message is the HTTP response.statusText. It surfaces any 4xx/5xx from the server with essentially no context (no URL, no status code number, no body), which makes it hard to diagnose. Callers are findNotificationContexts, findNotifications, findMessagesMeta, findMessagesGroups.","triggerScenarios":"Calling any find* method (findNotificationContexts/findNotifications/findMessagesMeta/findMessagesGroups) against /api/v1/request/communication/... when the server responds non-OK: 401/403 (bad/expired bearer token), 404 (wrong workspace or operation), 500 (server error).","commonSituations":"Expired or misconfigured auth token in this.token; wrong workspace name in the client config; server downtime or route renamed after API version change; retries exhausted (the throw happens inside retry, so the last failure is reported).","solutions":["Log response.status (not just statusText) in the client or at the call site to identify the actual HTTP code.","Verify the bearer token passed to the client is valid and not expired.","Confirm the workspace name and operation path match the deployed communication service API.","Check the server logs for the corresponding 5xx if status is 500.","Consider capturing response body in the thrown error for diagnostics (patch rest.ts)."],"exampleFix":"// before\nif (!response.ok) {\n  throw new Error(response.statusText)\n}\n// after\nif (!response.ok) {\n  throw new Error(`GET ${requestUrl} failed: ${response.status} ${response.statusText}`)\n}","handlingStrategy":"try-catch","validationCode":"function assertClientConfig(client) {\n  if (!client.token || typeof client.token !== 'string') throw new Error('rest-client: valid bearer token required before find calls')\n  if (!client.workspace) throw new Error('rest-client: workspace must be set')\n}","typeGuard":"function isHttpResponseOk(res: Response): res is Response & { ok: true } {\n  return res.ok\n}","tryCatchPattern":"try {\n  const msgs = await client.findMessagesMeta(params)\n} catch (e) {\n  // e.message is bare statusText — inspect it and add context\n  console.error(`findMessagesMeta failed: ${e.message}; check token/workspace`) \n  if (e.message === 'Unauthorized') await refreshToken()\n  throw e\n}","preventionTips":["Refresh bearer tokens before expiry; handle 401 by re-authenticating.","Validate workspace name/operation paths against the deployed API version.","Prefer capturing response.status, since statusText may be empty (HTTP/2).","Monitor communication service health before bulk find operations."],"tags":["http","fetch","rest","network","api"],"backgroundTag":"http-request-failed","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}