{"record":{"id":"6ea6df3152f9fab0","repo":"hcengineering/platform","slug":"text-response-body","errorCode":null,"errorMessage":"text (response body)","messagePattern":"text \\(response body\\)","errorType":"http","errorClass":"NotFoundError","httpStatus":404,"severity":"error","filePath":"foundations/core/packages/api-client/src/storage/client.ts","lineNumber":192,"sourceCode":"      chunks.push(chunk)\n    }\n    return Buffer.concat(chunks as any)\n  } else {\n    throw new TypeError('Unsupported data type')\n  }\n}\n\nasync function wrappedFetch (url: string | URL, init?: RequestInit): Promise<Response> {\n  let response: Response\n  try {\n    response = await fetch(url, init)\n  } catch (error: any) {\n    throw new NetworkError(`Network error ${error}`)\n  }\n  if (!response.ok) {\n    const text = await response.text()\n    if (response.status === 404) {\n      throw new NotFoundError(text)\n    } else {\n      throw new StorageError(text)\n    }\n  }\n  return response\n}\n\nexport function createStorageClient (\n  filesUrl: string,\n  uploadUrl: string,\n  token: string,\n  workspace: WorkspaceUuid\n): StorageClient {\n  return new StorageClientImpl(filesUrl, uploadUrl, token, workspace)\n}\n\nexport async function connectStorage (url: string, options: AuthOptions, config?: ServerConfig): Promise<StorageClient> {\n  config ??= await loadServerConfig(url)","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/core/packages/api-client/src/storage/client.ts#L174-L210","documentation":"wrappedFetch in the storage client converts failed HTTP responses into typed errors. When the server responds with a non-ok status, the response body text is captured and thrown: NotFoundError for 404, StorageError for any other failure. The error message is the raw response body, so the actual reason lives in the server's response text.","triggerScenarios":"Any storage API call (stat, response, remove) that reaches wrappedFetch and receives response.ok === false: missing blobs (404 -> NotFoundError), permission denied, malformed requests, or storage-server outages (other statuses -> StorageError).","commonSituations":"Requesting a blob ID that was deleted or never uploaded; wrong storage endpoint URL in config; expired or missing auth token causing 401/403; storage service temporarily down returning 5xx.","solutions":["Log the error message — it is the raw response body — to see the server's actual reason.","For 404: verify the blob/document ID exists before calling stat/response/remove, or treat NotFoundError as an expected miss.","Check the storage endpoint URL and credentials used to create the storage client.","Retry with backoff for 5xx statuses, as these usually indicate transient storage-service problems.","Capture response.status/text in the error for observability instead of discarding the status code."],"exampleFix":"// before\ntry {\n  await storage.stat(blobId)\n} catch (err) {\n  console.error('failed', err) // message is opaque body text\n}\n// after\nimport { NotFoundError } from '@hcengineering/api-client'\ntry {\n  await storage.stat(blobId)\n} catch (err) {\n  if (err instanceof NotFoundError) return null // expected miss\n  console.error('storage status/body:', err.message)\n  throw err\n}","handlingStrategy":"try-catch","validationCode":"// optionally probe before use\nconst res = await fetch(`${storageUrl}/${blobId}`, { method: 'HEAD' })\nif (res.status === 404) return null","typeGuard":"function isNotFound(err: unknown): err is NotFoundError {\n  return err instanceof NotFoundError\n}","tryCatchPattern":"try {\n  return await storage.stat(blobId)\n} catch (err) {\n  if (err instanceof NotFoundError) return null\n  if (err instanceof StorageError) console.error('storage:', err.message)\n  throw err\n}","preventionTips":["Always treat NotFoundError as an expected outcome, not a crash","Log err.message — it is the server's response body","Verify blob IDs exist before storage operations in UI flows","Retry only on non-404 StorageError with backoff"],"tags":["http","storage","error-handling"],"backgroundTag":"http-non-ok-response","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}