{"record":{"id":"859fb5931fd23251","repo":"toeverything/AFFiNE","slug":"link-preview-response-too-large","errorCode":null,"errorMessage":"Link preview response too large","messagePattern":"Link preview response too large","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"blocksuite/affine/shared/src/services/link-preview-service/response.ts","lineNumber":103,"sourceCode":"\nexport async function readLinkPreviewResponse(\n  response: Response,\n  maxBytes = 4 * 1024 * 1024\n) {\n  if (!response.ok || !response.body)\n    throw new Error('Link preview unavailable');\n  const reader = response.body.getReader();\n  const decoder = new TextDecoder();\n  let bytes = 0;\n  let json = '';\n  try {\n    for (;;) {\n      const { done, value } = await reader.read();\n      if (done) break;\n      bytes += value.byteLength;\n      if (bytes > maxBytes) {\n        await reader.cancel();\n        throw new Error('Link preview response too large');\n      }\n      json += decoder.decode(value, { stream: true });\n    }\n    json += decoder.decode();\n  } finally {\n    reader.releaseLock();\n  }\n  const data = parseLinkPreviewResponse(JSON.parse(json));\n  if (!data) throw new Error('Invalid link preview response');\n  return data;\n}\n","sourceCodeStart":85,"sourceCodeEnd":115,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/2af30773aecd567f09b346e7b72fc69143144057/blocksuite/affine/shared/src/services/link-preview-service/response.ts#L85-L115","documentation":"readLinkPreviewResponse enforces a size cap (default 4 MiB) while streaming the response body. If the accumulated byte count exceeds maxBytes, it cancels the reader and throws 'Link preview response too large'. This protects the client from downloading unbounded payloads from the preview service.","triggerScenarios":"The preview endpoint returns a JSON body larger than maxBytes (default 4*1024*1024 bytes); happens when a caller passes a smaller custom maxBytes and the response slightly exceeds it, or the backend misbehaves and streams an oversized document.","commonSituations":"A malicious or misconfigured preview server returning huge payloads; a caller lowering maxBytes below the typical response size; responses that embed very long transcripts (e.g. full YouTube transcripts) pushing past the limit.","solutions":["Increase maxBytes when calling readLinkPreviewResponse if legitimate responses exceed 4 MiB","Check the preview backend for runaway payload sizes (e.g. oversized transcripts or embedded data)","Handle the error with try-catch and fall back to a basic link card without preview data","If responses are legitimately large, stream/process them differently instead of buffering"],"exampleFix":"// before\nconst data = await readLinkPreviewResponse(res);\n// after\nconst data = await readLinkPreviewResponse(res, 16 * 1024 * 1024); // raise cap to 16 MiB","handlingStrategy":"try-catch","validationCode":"const contentLength = Number(response.headers.get('content-length') ?? 0);\nconst maxBytes = 4 * 1024 * 1024;\nif (contentLength > maxBytes) {\n  throw new Error('Preview response exceeds size limit');\n}","typeGuard":"null","tryCatchPattern":"try {\n  const data = await readLinkPreviewResponse(response);\n} catch (e) {\n  if (e.message === 'Link preview response too large') {\n    // skip preview or retry with a higher maxBytes\n  } else throw e;\n}","preventionTips":["Check content-length header against your maxBytes before reading","Pass an explicit maxBytes sized for your largest legitimate payloads","Be cautious lowering maxBytes below 4 MiB — typical responses with transcripts can be large","Treat oversized responses from untrusted servers as a signal to blocklist them"],"tags":["http","size-limit","stream","payload"],"backgroundTag":"payload-too-large","analyzedSha":"2af30773aecd567f09b346e7b72fc69143144057","analyzedAt":"2026-09-15T22:21:42.632Z","contentChangedAt":"2026-09-15T22:21:42.632Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}