toeverything/AFFiNE · warning · CommentAttachmentQuotaExceeded

comment_attachment_quota_exceeded

comment_attachment_quota_exceeded

Error message

You have exceeded the comment attachment size quota.

What it means

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`).

Source

Thrown at packages/backend/server/src/core/comment/resolver.ts:362

    description: 'Upload a comment attachment and return the access url',
  })
  async uploadCommentAttachment(
    @CurrentUser() me: UserType,
    @Args('workspaceId') workspaceId: string,
    @Args('docId') docId: string,
    @Args({ name: 'attachment', type: () => GraphQLUpload })
    attachment: FileUpload
  ) {
    await this.assertPermission(
      me,
      { workspaceId, docId },
      'Doc.Comments.Create'
    );

    const buffer = await readableToBuffer(attachment.createReadStream());
    // max attachment size is 10MB
    if (buffer.length > 10 * 1024 * 1024) {
      throw new CommentAttachmentQuotaExceeded();
    }

    const checkExceeded =
      await this.quota.getWorkspaceQuotaCalculator(workspaceId);
    const result = checkExceeded(buffer.length);
    if (result?.blobQuotaExceeded || result?.storageQuotaExceeded) {
      throw new CommentAttachmentQuotaExceeded();
    }

    const key = randomUUID();
    await this.commentAttachmentStorage.put(
      workspaceId,
      docId,
      key,
      attachment.filename ?? key,
      buffer,
      me.id
    );

View on GitHub (pinned to 26c515e050)

Solutions

  1. Pre-check `file.size <= 10 * 1024 * 1024` on the client before opening the upload stream and reject early with a UI message.
  2. Compress or transcode large media (resize images, transcode video) before upload.
  3. Truncate or chunk the attachment, or host large files out-of-band and link them.
  4. Surface the 10 MiB limit in the attachment picker so users self-filter.

Example fix

// before
await client.mutate({
  mutation: UPLOAD_COMMENT_ATTACHMENT,
  variables: { workspaceId, docId, attachment: { file } },
});

// after
const MAX = 10 * 1024 * 1024;
if (file.size > MAX) {
  toast(`Attachment exceeds the 10 MiB limit (got ${(file.size / 1048576).toFixed(1)} MiB).`);
  return;
}
await client.mutate({
  mutation: UPLOAD_COMMENT_ATTACHMENT,
  variables: { workspaceId, docId, attachment: { file } },
});
Defensive patterns

Strategy: validation

Validate before calling

// Hard client-side cap matching the server constant
const MAX_ATTACHMENT_BYTES = 10 * 1024 * 1024;

function withinAttachmentLimit(file: File): boolean {
  return file.size > 0 && file.size <= MAX_ATTACHMENT_BYTES;
}

if (!withinAttachmentLimit(file)) {
  toast(`Attachment must be between 1 byte and 10 MiB (got ${file.size} bytes).`);
  return;
}

Type guard

function isUploadableFile(value: unknown): value is File {
  return value instanceof File && typeof value.size === 'number' && value.size > 0;
}

Try / catch

try {
  await mutateUploadAttachment(workspaceId, docId, file);
} catch (e) {
  if (e?.graphQLErrors?.[0]?.extensions?.code === 'comment_attachment_quota_exceeded') {
    toast('Attachment is too large (10 MiB max).');
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: Users dragging in large screenshots/PDFs/videos; clients that don't pre-check file size; uploads from mobile cameras producing multi-MB images.

Related errors


AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12). Data as JSON: /api/errors/7b01f6b46736511d. Report an issue: GitHub.