chatwoot / chatwoot/chatwoot

Widget direct uploads classify videos and other files as images

Open
#15,313 1 comment 0 reactions 1 assignee View on GitHub

@vishnu-narayanan is already working on this.

Since Aug 4, 2026.

Bug
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:

https://github.com/chatwoot/chatwoot/blob/develop/app/controllers/api/v1/widget/messages_controller.rb

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
  1. Run a self-hosted Chatwoot installation with cloud storage configured.
  2. Set DIRECT_UPLOADS_ENABLED=true.
  3. Enable attachments for a website widget inbox.
  4. Send an MP4 video through the website widget.
  5. Open the conversation in the agent dashboard.
  6. Observe “This image is no longer available.”
  7. Inspect the message API response.
  8. Observe that the attachment has file_type: "image".
  9. Open the attachment’s data_url directly.
  10. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.