{"record":{"id":"741a09bced30aa9a","repo":"RocketChat/Rocket.Chat","slug":"failed-to-fetch-encrypted-pdf-response-status","errorCode":null,"errorMessage":"Failed to fetch encrypted PDF: ${response.status}","messagePattern":"Failed to fetch encrypted PDF: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/client/components/message/content/attachments/file/hooks/useOpenEncryptedPdf.ts","lineNumber":59,"sourceCode":"\n\t\tif (blobUrlRef.current) {\n\t\t\tURL.revokeObjectURL(blobUrlRef.current);\n\t\t\tblobUrlRef.current = undefined;\n\t\t}\n\n\t\tif (abortControllerRef.current) {\n\t\t\tabortControllerRef.current.abort();\n\t\t}\n\n\t\tconst abortController = new AbortController();\n\t\tabortControllerRef.current = abortController;\n\n\t\ttry {\n\t\t\tconst response = await fetch(getURL(link), {\n\t\t\t\tsignal: abortController.signal,\n\t\t\t});\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(`Failed to fetch encrypted PDF: ${response.status}`);\n\t\t\t}\n\t\t\tconst blob = await response.blob();\n\t\t\tif (abortController.signal.aborted || abortControllerRef.current !== abortController) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst blobUrl = URL.createObjectURL(blob);\n\t\t\tblobUrlRef.current = blobUrl;\n\t\t\topenDocumentViewer(blobUrl, format, title ?? '');\n\t\t} catch (error: any) {\n\t\t\tif (error.name !== 'AbortError') {\n\t\t\t\tconsole.error('Error opening preview of encrypted PDF', error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t};\n\n\treturn openEncryptedPdf;\n};","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/client/components/message/content/attachments/file/hooks/useOpenEncryptedPdf.ts#L41-L77","documentation":"Thrown by useOpenEncryptedPdf when the fetch() for an encrypted PDF attachment returns a non-ok HTTP status (response.ok === false). The message embeds response.status (e.g. 401, 403, 404, 500) so the developer can see why the media fetch failed. The fetch targets getURL(link) on the media host; non-2xx means the resource could not be retrieved.","triggerScenarios":"The encrypted PDF blob endpoint returned 401 (token expired/not supplied), 403 (no permission for the room/attachment), 404 (attachment deleted or wrong link), or 5xx (media store/S3 failure). The check `if (!response.ok)` fires before reading the blob and throws the templated message.","commonSituations":"E2E encryption key not available so the server rejects the fetch; the user lacks 'preview-file' permission; the attachment was deleted; the S3/gridfs backing store is unreachable; the auth cookie/token was not sent with the fetch (CORS or credentials config).","solutions":["Read response.status from the message: 401/403 → auth/permission, 404 → missing attachment, 5xx → server/storage.","For 401/403, verify the session token is sent with the media request and the user has access to the room/attachment.","For 404, confirm the attachment still exists (it may have been purged).","Ensure credentials are included in the fetch if the media host differs from the app host (sameSite/CORS).","If the PDF exceeds pdfPreviewSizeLimitInBytes the hook downloads instead of previewing — confirm size handling is intended."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-check access before fetching the encrypted PDF\nif (!hasAtLeastOnePermission('preview-file', roomId)) {\n  throw new Error('Permission denied');\n}","typeGuard":"function isOkResponse(r: Response): boolean {\n  return r.ok;\n}","tryCatchPattern":"try {\n  await openEncryptedPdf(link, title, size, format, openViewer);\n} catch (e) {\n  const status = (e as Error).message.match(/(\\d+)$/)?.[1];\n  if (status === '401' || status === '403') { redirectToLogin(); }\n  else if (status === '404') { showAttachmentMissing(); }\n}","preventionTips":["Ensure the auth token/cookie is sent with the media fetch (credentials config).","Verify the user has preview/read permission for the attachment's room.","Parse the trailing status code from the message to branch handling."],"tags":["e2e-encryption","pdf","fetch","attachment","http-status"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}