Widget direct uploads classify videos and other files as images
@vishnu-narayanan is already working on this.
Since Aug 4, 2026.
- Dominant language
- Ruby
- Stars
- 37k
- Forks
- 9k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 97
Description
Describe the bug
When DIRECT_UPLOADS_ENABLED=true, non-image attachments sent through the website widget are stored with file_type: image.
The upload itself succeeds and the Active Storage data_url is valid. For example, an uploaded MP4 plays normally when its data_url is opened directly. However, the message API reports the attachment as an image, causing the agent
dashboard to render it through the image component and display:
This image is no longer available.
The widget sends direct uploads as Active Storage signed IDs. The widget messages controller only assigns file_type when the attachment is an ActionDispatch::Http::UploadedFile:
Signed IDs are strings, so that branch is skipped and the attachment retains the database default of image.
Chatwoot already provides file_type_by_signed_id for this purpose:
https://github.com/chatwoot/chatwoot/blob/develop/app/helpers/file_type_helper.rb
The regular message builder already handles both signed IDs and multipart uploads, but the widget controller does not.
To Reproduce
- Run a self-hosted Chatwoot installation with cloud storage configured.
- Set
DIRECT_UPLOADS_ENABLED=true. - Enable attachments for a website widget inbox.
- Send an MP4 video through the website widget.
- Open the conversation in the agent dashboard.
- Observe “This image is no longer available.”
- Inspect the message API response.
- Observe that the attachment has
file_type: "image". - Open the attachment’s
data_urldirectly. - Observe that the video plays normally.
Expected behavior
The widget controller should resolve the Active Storage signed ID, inspect the blob’s content type, and store the attachment as video.
The same behavior should correctly classify audio and document uploads.
Environment
Docker
Cloud Provider
AWS
Platform
Browser
Operating system
Linux Mint 22.2 (Zara)
Browser and version
No response
Docker
Docker Engine - Community 29.6.2
API version: 1.55
containerd: v2.2.6
runc: 1.3.6
Storage driver: overlayfs
Cgroup driver: systemd (v2)
Docker Compose
Docker Compose v5.3.1 (docker compose plugin)
The legacy docker-compose binary is not installed.
Additional context
The expected classification logic already exists in file_type_by_signed_id and is used by the regular message builder.
A minimal fix would apply the same logic in the widget messages controller:
attachment.file_type = if uploaded_attachment.is_a?(String)
helpers.file_type_by_signed_id(uploaded_attachment)
else
helpers.file_type(uploaded_attachment&.content_type)
end
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.