{"record":{"id":"019cf0b1c27beb81","repo":"hcengineering/platform","slug":"await-response-text","errorCode":null,"errorMessage":"await response.text()","messagePattern":"await response\\.text\\(\\)","errorType":"exception","errorClass":"StorageError","httpStatus":null,"severity":"error","filePath":"foundations/core/packages/api-client/src/storage/client.ts","lineNumber":118,"sourceCode":"  }\n\n  async put (objectName: string, stream: Readable | Buffer | string, contentType: string, size?: number): Promise<Blob> {\n    const buffer = await toBuffer(stream)\n    const file = new File([new Uint8Array(buffer)], objectName, { type: contentType })\n    const formData = new FormData()\n    formData.append('file', file)\n    let response\n    try {\n      response = await fetch(this.uploadUrl, {\n        method: 'POST',\n        body: formData,\n        headers: { ...this.headers }\n      })\n    } catch (error: any) {\n      throw new NetworkError(`Network error ${error}`)\n    }\n    if (!response.ok) {\n      throw new StorageError(await response.text())\n    }\n    const result = (await response.json()) as BlobUploadResult[]\n    if (Object.hasOwn(result[0], 'id')) {\n      const fileResult = result[0] as BlobUploadSuccess\n      return {\n        _class: core.class.Blob,\n        _id: fileResult.id as Ref<Blob>,\n        space: core.space.Configuration,\n        modifiedOn: fileResult.metadata.lastModified,\n        modifiedBy: core.account.System,\n        provider: '',\n        contentType: fileResult.metadata.contentType,\n        etag: fileResult.metadata.etag,\n        version: null,\n        size: fileResult.metadata.size\n      }\n    } else {\n      const error = (result[0] as BlobUploadError) ?? 'Unknown error'","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/foundations/core/packages/api-client/src/storage/client.ts#L100-L136","documentation":"When the upload POST completes but the server responds with a non-ok status, put() reads the response body text and throws it as a StorageError. The message is whatever error text the upload service returned (HTML error pages, JSON error bodies, or plain text like 'Unauthorized').","triggerScenarios":"Calling storageClient.put(...) and receiving 401 (invalid workspace token), 403, 404 (bad UPLOAD_URL path), 413 (payload too large), or 5xx from the upload service.","commonSituations":"Expired or wrongly-scoped bearer token in the StorageClient; upload service rejecting files above a size limit set at the proxy; UPLOAD_URL path changed in server config so requests hit a 404 page; auth middleware returning HTML login pages.","solutions":["Log the StorageError message — it contains the server's error body which names the cause (Unauthorized, Payload Too Large, etc.).","Regenerate the workspace token and recreate the storage client via connectStorage.","Check UPLOAD_URL in server config matches the running upload service route.","Reduce file size or raise proxy/upload body-size limits for 413 errors.","Verify Authorization header reaches the service (not stripped by a proxy)."],"exampleFix":"// before\nawait storage.put(name, stream, contentType) // StorageError: <html>401...</html>\n// after\ntry {\n  await storage.put(name, stream, contentType)\n} catch (err) {\n  if (err instanceof StorageError && /unauthorized/i.test(err.message)) {\n    storage = await connectStorage(url, options) // fresh token\n    return storage.put(name, stream, contentType)\n  }\n  throw err\n}","handlingStrategy":"try-catch","validationCode":"// Ensure a fresh token before constructing/using the storage client\nif (Date.now() >= tokenExpiresAt - 60_000) {\n  token = (await getWorkspaceToken(url, options, config)).token\n  storage = createStorageClient(filesUrl, uploadUrl, token, workspace)\n}","typeGuard":"function isStorageError(e: unknown): e is StorageError {\n  return e instanceof StorageError\n}","tryCatchPattern":"try {\n  return await storage.put(name, stream, contentType)\n} catch (e) {\n  if (isStorageError(e)) {\n    // message contains the server response text, e.g. 'Unauthorized' or 'Payload Too Large'\n    if (/unauthorized|forbidden/i.test(e.message)) {\n      // re-authenticate and retry once\n    }\n  }\n  throw e\n}","preventionTips":["Refresh workspace tokens before they expire.","Keep UPLOAD_URL config in sync with the deployed upload service routes.","Enforce file-size limits client-side to avoid 413 rejections.","Check that proxies forward the Authorization header."],"tags":["storage","upload","http-error","authentication"],"backgroundTag":"http-non-ok-response","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}