{"record":{"id":"7b01f6b46736511d","repo":"toeverything/AFFiNE","slug":"comment-attachment-quota-exceeded","errorCode":"comment_attachment_quota_exceeded","errorMessage":"You have exceeded the comment attachment size quota.","messagePattern":"You have exceeded the comment attachment size quota\\.","errorType":"exception","errorClass":"CommentAttachmentQuotaExceeded","httpStatus":402,"severity":"warning","filePath":"packages/backend/server/src/core/comment/resolver.ts","lineNumber":362,"sourceCode":"    description: 'Upload a comment attachment and return the access url',\n  })\n  async uploadCommentAttachment(\n    @CurrentUser() me: UserType,\n    @Args('workspaceId') workspaceId: string,\n    @Args('docId') docId: string,\n    @Args({ name: 'attachment', type: () => GraphQLUpload })\n    attachment: FileUpload\n  ) {\n    await this.assertPermission(\n      me,\n      { workspaceId, docId },\n      'Doc.Comments.Create'\n    );\n\n    const buffer = await readableToBuffer(attachment.createReadStream());\n    // max attachment size is 10MB\n    if (buffer.length > 10 * 1024 * 1024) {\n      throw new CommentAttachmentQuotaExceeded();\n    }\n\n    const checkExceeded =\n      await this.quota.getWorkspaceQuotaCalculator(workspaceId);\n    const result = checkExceeded(buffer.length);\n    if (result?.blobQuotaExceeded || result?.storageQuotaExceeded) {\n      throw new CommentAttachmentQuotaExceeded();\n    }\n\n    const key = randomUUID();\n    await this.commentAttachmentStorage.put(\n      workspaceId,\n      docId,\n      key,\n      attachment.filename ?? key,\n      buffer,\n      me.id\n    );","sourceCodeStart":344,"sourceCodeEnd":380,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/26c515e050211269e911f7d9cfe162a26c83ed98/packages/backend/server/src/core/comment/resolver.ts#L344-L380","documentation":"Thrown by `uploadCommentAttachment` when the in-memory buffer exceeds the hard-coded 10 MiB ceiling (`buffer.length > 10 * 1024 * 1024`). This is an absolute per-file guard independent of any workspace quota and fires before the workspace quota calculator runs. Code is `comment_attachment_quota_exceeded` (category `quota_exceeded`).","triggerScenarios":"Uploading any single attachment larger than 10 MiB through the `uploadCommentAttachment` mutation; streaming a large file whose realized buffer length crosses 10 MiB even if the client低估ed the size.","commonSituations":"Users dragging in large screenshots/PDFs/videos; clients that don't pre-check file size; uploads from mobile cameras producing multi-MB images.","solutions":["Pre-check `file.size <= 10 * 1024 * 1024` on the client before opening the upload stream and reject early with a UI message.","Compress or transcode large media (resize images, transcode video) before upload.","Truncate or chunk the attachment, or host large files out-of-band and link them.","Surface the 10 MiB limit in the attachment picker so users self-filter."],"exampleFix":"// before\nawait client.mutate({\n  mutation: UPLOAD_COMMENT_ATTACHMENT,\n  variables: { workspaceId, docId, attachment: { file } },\n});\n\n// after\nconst MAX = 10 * 1024 * 1024;\nif (file.size > MAX) {\n  toast(`Attachment exceeds the 10 MiB limit (got ${(file.size / 1048576).toFixed(1)} MiB).`);\n  return;\n}\nawait client.mutate({\n  mutation: UPLOAD_COMMENT_ATTACHMENT,\n  variables: { workspaceId, docId, attachment: { file } },\n});","handlingStrategy":"validation","validationCode":"// Hard client-side cap matching the server constant\nconst MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;\n\nfunction withinAttachmentLimit(file: File): boolean {\n  return file.size > 0 && file.size <= MAX_ATTACHMENT_BYTES;\n}\n\nif (!withinAttachmentLimit(file)) {\n  toast(`Attachment must be between 1 byte and 10 MiB (got ${file.size} bytes).`);\n  return;\n}","typeGuard":"function isUploadableFile(value: unknown): value is File {\n  return value instanceof File && typeof value.size === 'number' && value.size > 0;\n}","tryCatchPattern":"try {\n  await mutateUploadAttachment(workspaceId, docId, file);\n} catch (e) {\n  if (e?.graphQLErrors?.[0]?.extensions?.code === 'comment_attachment_quota_exceeded') {\n    toast('Attachment is too large (10 MiB max).');\n    return;\n  }\n  throw e;\n}","preventionTips":["Pre-check `file.size <= 10 * 1024 * 1024` before opening the upload stream.","Show the 10 MiB limit in the attachment picker.","Compress images/transcode media before upload to stay well under the cap."],"tags":["graphql","comments","attachments","quota","upload","file-size"],"backgroundTag":null,"analyzedSha":"26c515e050211269e911f7d9cfe162a26c83ed98","analyzedAt":"2026-08-12T13:15:16.447Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}