chatwoot/spec
JoseGrdar 7acbe8b3ff
fix(whatsapp): truncate location fallback_title to 255 chars to avoid silent message drop (#14517)
## Summary

`Whatsapp::IncomingMessageBaseService#attach_location` builds a
`fallback_title` by concatenating `location['name']` and
`location['address']` with no length cap, then stores it directly into
`Attachment#fallback_title`. `ApplicationRecord` enforces a generic
255-character limit on string columns, so any WhatsApp location whose
`"#{name}, #{address}"` exceeds 255 chars (a common case for Google
Places that include a long full address) raises
`ActiveRecord::RecordInvalid` deep inside the Sidekiq job. The message
and attachment INSERTs are part of the same transaction, so the whole
thing rolls back. Sidekiq retries once; the retry dedup-skips the wamid
silently and exits without an error. **Result: the message is
irrecoverably lost — no row in `messages`, no entry in the UI, no
outgoing webhook, no clue for the operator.**

Confirmed in `v4.13.0`, `v4.14.0`, and `develop` (commit `f33e469`,
2026-05-20). No upstream issue found before opening this PR.

## How to reproduce

1. From WhatsApp, share a Google Place whose `name + ", " + address` is
> 255 chars. The Spanish business address `Gremi de Fusters, 33,
Edificio VIP Asima, Piso 2, Local 2, Norte, 07009 Polígon industrial de
Son Castelló, Illes Balears, España` (132 chars) used as both `name` and
`address` is enough.
2. Sidekiq logs:
   ```
   ERROR ActiveRecord::RecordInvalid: Validation failed:
   Attachments fallback title is too long (maximum is 255 characters)
   ```
3. The `messages` table has no row. The conversation UI shows nothing
for that timestamp.
4. The first retry "Performed" successfully but creates nothing — the
dedup-by-source-id silently swallows the failure.

## Fix

Cap the existing concatenated title at 255 chars via `.first(255)`.
Minimal change, no behavioural difference for any message shorter than
the limit, prevents the silent data loss for any longer ones.

```diff
-    location_name = location['name'] ? "#{location['name']}, #{location['address']}" : ''
+    location_name = (location['name'] ? "#{location['name']}, #{location['address']}" : '').first(255)
```

## Alternatives considered

- **Increase the validation limit on `Attachment#fallback_title`**: more
invasive; would touch other inbound channels and possibly require a DB
column change.
- **Use `name` alone (no concat)**: cleaner semantically (in many real
payloads `name == address`), but changes user-visible behaviour. Left as
a follow-up if desired.
- **Truncate with ellipsis**: cosmetic only; deferred.

This PR is intentionally minimal so it can be merged on its own.

---------

Co-authored-by: Sony Mathew <sony@chatwoot.com>
Co-authored-by: Sony Mathew <2040199+sony-mathew@users.noreply.github.com>
2026-06-03 12:50:21 +05:30
..
actions fix: Skip redundant contact saves in ContactIdentifyAction (#13778) 2026-03-11 21:40:38 -07:00
assets fix: standardize contact company field on company_name (#14099) 2026-04-27 18:43:26 +05:30
builders feat(whatsapp): Add support for voice messages (#14606) 2026-06-02 15:33:32 +04:00
channels fix: Move contact events to account stream rather than individual user stream (#11082) 2025-03-13 17:46:48 -07:00
config feat: add GuideJar embed support in HC (#13944) 2026-03-30 14:19:02 +05:30
configs chore: Enable the new Rubocop rules (#7122) 2023-05-19 14:37:10 +05:30
controllers fix(microsoft): prevent OAuth admin consent loop (#13962) 2026-06-03 12:05:25 +05:30
dispatchers Non blocking event dispatch (#652) 2020-03-29 19:18:30 +05:30
drops feat: Add the support for custom attributes in message variables (#8511) 2023-12-08 14:13:35 -08:00
enterprise fix(contacts): align contact export permissions (#14601) 2026-06-01 13:58:57 +05:30
factories feat: Ability to specify the authentication type for imap server (#12306) 2026-05-08 16:40:15 +05:30
finders feat(rollup): report builder abstraction [2/3] (#13798) 2026-04-20 11:15:48 +05:30
fixtures fix(mailbox): render inline images without Content-Disposition (#11949) 2026-05-06 18:56:31 +05:30
helpers feat: Implemented search results page functionality (#11086) 2026-06-02 15:19:23 +05:30
integration Fix url in emails, add frontendURL helper (#19) 2019-08-25 19:59:28 +05:30
jobs feat: show processing status for one-off campaigns (#14592) 2026-06-01 16:47:17 +05:30
lib fix: Support allowlisted private API inbox webhooks (#14548) 2026-05-26 17:03:19 +05:30
listeners revert: restore conversation unread count feature flag (#14623) 2026-06-02 21:11:48 +05:30
mailboxes fix(mailbox): render inline images without Content-Disposition (#11949) 2026-05-06 18:56:31 +05:30
mailers fix: validate OpenAI hook credentials (#14068) 2026-05-18 14:08:57 +05:30
models revert: restore conversation unread count feature flag (#14623) 2026-06-02 21:11:48 +05:30
policies chore: Enforce custom role permissions on conversation access (#12583) 2025-10-22 20:23:37 -07:00
presenters fix: index email subject from conversation for outbound messages (#14122) 2026-04-22 20:36:35 +05:30
requests/api/v1 feat: allow disabling 2FA with a backup code (#14102) 2026-04-28 10:09:41 +07:00
services fix(whatsapp): truncate location fallback_title to 255 chars to avoid silent message drop (#14517) 2026-06-03 12:50:21 +05:30
support feat: base layer for unread counts (store, counter and builder) (1/3)[CW-6851] (#14368) 2026-05-20 14:26:21 +05:30
swagger feat: validate OpenAPI spec using Skooma (#13623) 2026-03-10 18:33:55 -07:00
coverage_helper.rb ci(circleci): switch coverage reporting to Qlty orb (#12337) 2025-08-31 00:39:34 +05:30
rails_helper.rb feat: base layer for unread counts (store, counter and builder) (1/3)[CW-6851] (#14368) 2026-05-20 14:26:21 +05:30
spec_helper.rb ci(circleci): switch coverage reporting to Qlty orb (#12337) 2025-08-31 00:39:34 +05:30
test_helper.rb ci(circleci): switch coverage reporting to Qlty orb (#12337) 2025-08-31 00:39:34 +05:30