{"record":{"id":"2be535e4f2c38b33","repo":"hcengineering/platform","slug":"request-failed","errorCode":null,"errorMessage":"Request failed","messagePattern":"Request failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/kvs-client/src/client.ts","lineNumber":153,"sourceCode":"\n    if (options.returnNullOn404 === true && response.status === 404) {\n      return null\n    }\n\n    if (options.acceptNotFound === true && response.status === 404) {\n      return null\n    }\n\n    if (!response.ok) {\n      try {\n        const errorBody = await response.json()\n        if (errorBody?.error != null) {\n          throw new PlatformError(errorBody?.error)\n        }\n      } catch (e) {\n        // Ignore JSON parsing errors\n      }\n      throw new Error(options.errorMessage ?? 'Request failed')\n    }\n\n    // Parse JSON response when needed\n    const contentType = response.headers.get('content-type')\n    if (\n      response.status !== 204 &&\n      (options.method === 'GET' || (contentType != null && contentType.includes('application/json')))\n    ) {\n      return await response.json()\n    }\n\n    return null\n  }\n\n  private async fetchWithRetry (url: string, init: RequestInit): Promise<Response> {\n    const timeout = Date.now() + this.retryTimeoutMs\n    const connectionErrorCodes = ['ECONNRESET', 'ECONNREFUSED', 'ENOTFOUND']\n    let intervalMs = 25","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/packages/kvs-client/src/client.ts#L135-L171","documentation":"Generic fallback thrown by sendRequest when the server returned a non-OK status but no structured `error` field could be extracted from the response body (JSON parsing failed or `error` was absent), and no `options.errorMessage` override was supplied. It means the request failed at the HTTP level but the client could not determine a more specific reason.","triggerScenarios":"setValue/getValue/deleteKey/listKeys receiving an HTTP error response (4xx/5xx) with a non-JSON body, an empty body, or JSON lacking an `error` field.","commonSituations":"A gateway/proxy returning HTML error pages (502/504), the service being down or restarting, a wrong URL hitting a different server that doesn't return the expected error shape, or CORS intercepting the response body in browsers.","solutions":["Check the actual HTTP status/network traffic (browser devtools, service logs) to find the real cause.","Confirm the baseUrl points at the correct key-value API endpoint and is reachable.","Pass `options.errorMessage` in the request options to get a more descriptive error for your call site.","Retry with backoff if the failure is transient (5xx/gateway errors)."],"exampleFix":"// before\nawait client.getValue('user:42')\n// after\nawait client.getValue('user:42', { errorMessage: 'Failed to load user preference' })","handlingStrategy":"retry","validationCode":"try {\n  const health = await fetch(baseUrl + '/health')\n  if (!health.ok) throw new Error('KVS service unhealthy before request')\n} catch { /* service unreachable — fail early */ }","typeGuard":"null","tryCatchPattern":"try {\n  await client.setValue(key, value, { errorMessage: 'Failed to save setting' })\n} catch (e) {\n  if (e.message === 'Failed to save setting') {\n    // generic HTTP failure — check status/service health, consider retry\n  } else throw e\n}","preventionTips":["Pass options.errorMessage on important calls to make fallback errors descriptive.","Monitor the KVS service health and alert on 5xx spikes.","Use retries with exponential backoff for idempotent operations.","Check gateway/proxy config if HTML error pages appear in logs."],"tags":["http","server-error","fallback","kvs"],"backgroundTag":"http-request-failed","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}