CometChat.createUploadFileRequest(receiverId, receiverType) returns an UploadFileRequest — the entry point for uploading files directly to storage with per-file progress, success, and failure. Upload is decoupled from sending: each uploaded file yields an Attachment (carrying a hosted URL), which you then attach to a MediaMessage and send with sendMediaMessage().
A request object is scoped to one destination (receiverId / receiverType) and one upload batch. This is the recommended way to build a multi-attachment composer: create a request, upload a batch of files, show a progress bar per file, let the user remove or retry individual files, then send them as a single media message with multiple attachments (or split across several).
Why upload separately instead of passing files to
sendMediaMessage()?The classic path (passing a files list straight to the MediaMessage constructor) uploads and sends in one blocking call — you get no progress, no per-file remove, and no per-file retry. An UploadFileRequest moves the upload out of the send call so you can drive a rich composer UI, then send instantly because the files are already hosted.The upload-then-send flow
1
Create a request
Call
CometChat.createUploadFileRequest(receiverId, receiverType). The recipient is required — the server uses it to apply role- and scope-based access control before issuing upload URLs.2
Upload
Call
request.uploadAttachments(items, listener), where each UploadAttachment pairs a file with an app-supplied fileId (required) that is echoed back on every event, so you can map callbacks to your UI rows. Validation, presigning, and the byte transfer run asynchronously and report through the listener.3
Track progress & handle failures
Your
UploadFileListener receives onFileProgress per file, then onFileUploaded (success), onFileError (rejected — not retryable), or onFileFailure (failed — retryable). Use request.removeAttachment() or request.retryAttachment() as the user acts.4
Collect attachments
Each
onFileUploaded hands you an Attachment with a hosted URL. You can also read them from the request at any time with request.getAttachments().5
Build & send the message
Put the attachments on a
MediaMessage with attachments: and call sendMediaMessage(). Because the attachments already have URLs, the message is sent as JSON — no re-upload.6
Clean up
Call
request.clearAll() after a successful send (or to abandon the composer) to release the batch from memory.Create an upload request
Create anUploadFileRequest scoped to one destination, then upload files into it. The request owns a single batch — every file shares one batchId — and you pair each file with a fileId you choose, so you can correlate progress and errors back to your own UI.
- Dart
uploadAttachments again on the same request to add more files to the same batch (the user picks more, pastes, or drags another in). For a single file, request.uploadAttachment(fileId, file, listener) is the convenience form.
On web — or anywhere you only hold bytes, such as a clipboard paste — build the file from bytes instead:
- Dart
Configure the request
receiverId / receiverType are fixed when you create the request; the server authorizes every upload against that conversation once role-based access control is enabled. The rest are optional and must be set before the batch is first used (they throw once it is):
Track progress and completion
Pass anUploadFileListener to uploadAttachments (it receives that call’s files), or register a batch-wide one with request.addUploadListener(...). UploadFileListener ships default no-op callbacks, so extend it and override only the ones you need.
- Dart
onFileError and onFileFailure are deliberately different: an error will never succeed as-is, so surface it and let the user remove the file; a failure is worth a retry. onComplete fires when the batch drains — nothing left in flight.
You can also poll the batch at any point instead of tracking events:
- Dart
Retry, remove, and clear
- Dart
removeAttachment is safe in any state and frees the file’s slot against file.count.max, so the user can pick a replacement. retryAttachment is a no-op on a rejected file (onFileError — not retryable).
Read the limits
- Dart
getMaxAttachmentCount() to cap your picker so the user cannot select more than the message allows, and getMaxAttachmentSize() to reject an over-sized file before uploading it.
Send the uploaded attachments
Attach theAttachment objects the batch produced — the ones you kept from onFileUploaded, or request.getAttachments() — to one MediaMessage. Use attachments (not files — the bytes are already on storage), and set type to the kind those attachments are. Call request.clearAll() once the message is sent to release the batch.
Keep one message to a single kind.
type is what a receiving UI picks its bubble from, so images in a message typed file render as file cards rather than a grid. If the user picked a mix, group the attachments by kind and send one message per kind — this is exactly what the UI Kit’s composer does, tagging each message with a shared batchId so they display as one group.- Dart
Error handling
The non-retryable codes arrive via
onFileError, the retryable ones via onFileFailure.
Next Steps
Send A Message
Send text, media, and custom messages
Multiple Attachments
Send several attachments in one media message
Receive Messages
Listen for incoming messages in real-time
Threaded Messages
Upload into a thread with setParentMessageId