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
- Sign in, then open a channel.
- Attach a video larger than 10 MB.
- See a tile appear and turn to the failed state at once. No bytes are sent.
- Tap Retry. See the same error.
Acceptance criteria
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.
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 underapps/webapp/src/components/chatroom/.components/MessageComposer/hooks/useComposerAttachments.ts:116-135).validateChatMediaFilehas no upper size check (utils/chatMediaMime.ts:186-199). It readsfile.sizeonly to skip the extension check on an empty file.uploadChatMedia. It throws "File must be 10 MB or smaller" when the file is larger thanCHAT_MEDIA_MAX_BYTES, which is 10,485,760 bytes (utils/uploadChatMedia.ts:88-90,utils/messageMediaPaths.ts:8).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.retryAttachmentenqueues the same file again (components/MessageComposer/hooks/useComposerAttachments.ts:164-173). For an oversized file, it fails again.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
Acceptance criteria
CHAT_MEDIA_MAX_BYTESis refused when it is added. A toast names the 10 MB limit, and no tile appears..jpgwhosefile.typeis empty.AttachmentStripsays 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, ornull.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 rawfile.type.validateChatMediaFile()falls back to the file name whenfile.typeis empty. The add-time size check must agree with the downscale step.retryAttachment(id)and the attachment error state.ComposerAttachment— a failed attachment carriesstatus: 'error'and theerrortext. 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.