Skip to content

Refuse an oversized chat file when it is added, not after it fails #280

Description

@HMarzban

Problem

The composer accepts a file of any size, then fails it before the upload starts. The failed tile offers Retry, which can never succeed.

On 14ab7f9c1. Paths are under apps/webapp/src/components/chatroom/.

  • Adding files checks the count and the type only (components/MessageComposer/hooks/useComposerAttachments.ts:116-135). validateChatMediaFile has no upper size check (utils/chatMediaMime.ts:186-199). It reads file.size only to skip the extension check on an empty file.
  • The size check runs inside uploadChatMedia. It throws "File must be 10 MB or smaller" when the file is larger than CHAT_MEDIA_MAX_BYTES, which is 10,485,760 bytes (utils/uploadChatMedia.ts:88-90, utils/messageMediaPaths.ts:8).
  • Most images are downscaled before that check (utils/chatMediaUploadRunner.ts:16-68, called at :193-195), so a large photo can still pass. GIF, HEIC, and HEIF images are not downscaled (:14-17). Video, audio, and other files are not downscaled either.
  • retryAttachment enqueues the same file again (components/MessageComposer/hooks/useComposerAttachments.ts:164-173). For an oversized file, it fails again.
  • The chatroom rules and the design system give every failed compact tile a Retry (apps/webapp/src/components/chatroom/CLAUDE.md:63, .cursor/docs/design-system.md:658).

So a user who attaches a 50 MB video sees a failed tile at once, and a Retry that always fails. No bytes are sent.

Steps to reproduce

  1. Sign in, then open a channel.
  2. Attach a video larger than 10 MB.
  3. See a tile appear and turn to the failed state at once. No bytes are sent.
  4. Tap Retry. See the same error.

Acceptance criteria

  • A video, an audio file, or any other non-image file larger than CHAT_MEDIA_MAX_BYTES is refused when it is added. A toast names the 10 MB limit, and no tile appears.
  • An image larger than the limit either goes through downscale or is refused when it is added. This includes a .jpg whose file.type is empty.
  • A GIF, HEIC, or HEIF image larger than the limit is refused when it is added, like a video.
  • An attachment with a size failure shows Remove only, not Retry, on the full tile and on the compact tile. An attachment that failed for a network or server reason still shows Retry.
  • The chatroom rule on full-tile retry for the compact AttachmentStrip says that a size failure has no Retry. So does the failed row of the design-system AttachmentStrip table.

Agent Brief

Category: bug
Summary: Refuse a file that can never fit the 10 MB limit when it is added, and show no Retry for a size failure.

Current behavior:
Add-time validation checks count and type only. The size check runs just before upload, so an oversized video becomes a failed tile whose Retry always fails.

Desired behavior:
Add-time validation refuses a file that can never fit the 10 MB limit, with a toast. JPEG, PNG, WebP, and BMP images still get downscaled before the limit applies. A size failure shows no Retry.

Key interfaces:

  • validateChatMediaFile(file) — returns a user-facing error, or null.
  • CHAT_MEDIA_MAX_BYTES — 10,485,760 bytes.
  • uploadChatMedia() — holds the current size check. Keep it. It is the only check for an image that is still too large after downscale.
  • downscaleChatMediaImage() — reads the raw file.type. validateChatMediaFile() falls back to the file name when file.type is empty. The add-time size check must agree with the downscale step.
  • retryAttachment(id) and the attachment error state.
  • ComposerAttachment — a failed attachment carries status: 'error' and the error text. Today no field marks an error as permanent.

Out of scope

Notes

The evidence is a code trace on 14ab7f9c1. It was not run in a browser.

Activity

  1. added a commit that references this issue on Sep 22, 2026
    7570f5d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ChatRelated to chat featuresUIbugSomething isn't workinggood first issueGood for newcomers

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions