From 6d26e7930ae14e4abe72821e863dc8b28e3ab070 Mon Sep 17 00:00:00 2001 From: Sony Mathew Date: Thu, 11 Jun 2026 15:15:14 +0530 Subject: [PATCH] fix(contacts): truncate inbound contact names (IMAP sender display names) (#14631) ## Description Truncates long contact names in `ContactInboxWithContactBuilder` before persisting them, so inbound IMAP sender display names over the `contacts.name` 255-character limit no longer raise `ActiveRecord::RecordInvalid` from `Inboxes::FetchImapEmailsJob`. This keeps email ingestion moving while preserving the existing contact name length constraint. Linear ticket: [https://linear.app/chatwoot/issue/CW-7263/sentry-active-record-invalid-contact-create-from-imap-fetch-job](https://linear.app/chatwoot/issue/CW-7263/sentry-active-record-invalid-contact-create-from-imap-fetch-job) ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## How Has This Been Tested? - [x] `bundle exec rspec spec/builders/contact_inbox_with_contact_builder_spec.rb` - [x] `bundle exec rspec spec/mailboxes/imap/imap_mailbox_spec.rb` - [x] `bundle exec rubocop app/builders/contact_inbox_with_contact_builder.rb spec/builders/contact_inbox_with_contact_builder_spec.rb` ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes --- .../contact_inbox_with_contact_builder.rb | 7 ++++++- app/models/application_record.rb | 5 ++++- .../contact_inbox_with_contact_builder_spec.rb | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/app/builders/contact_inbox_with_contact_builder.rb b/app/builders/contact_inbox_with_contact_builder.rb index 2c0e6087e..2ba9179ed 100644 --- a/app/builders/contact_inbox_with_contact_builder.rb +++ b/app/builders/contact_inbox_with_contact_builder.rb @@ -50,7 +50,7 @@ class ContactInboxWithContactBuilder def create_contact account.contacts.create!( - name: contact_attributes[:name] || ::Haikunator.haikunate(1000), + name: contact_name, phone_number: contact_attributes[:phone_number], email: contact_attributes[:email], identifier: contact_attributes[:identifier], @@ -59,6 +59,11 @@ class ContactInboxWithContactBuilder ) end + def contact_name + name = contact_attributes[:name] || ::Haikunator.haikunate(1000) + name.truncate(ApplicationRecord::MAX_STRING_COLUMN_LENGTH, omission: '') + end + def find_contact contact = find_contact_by_identifier(contact_attributes[:identifier]) contact ||= find_contact_by_email(contact_attributes[:email]) diff --git a/app/models/application_record.rb b/app/models/application_record.rb index c6877c883..0cb3f7de2 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -1,4 +1,7 @@ class ApplicationRecord < ActiveRecord::Base + MAX_STRING_COLUMN_LENGTH = 255 + MAX_TEXT_COLUMN_LENGTH = 20_000 + include Events::Types self.abstract_class = true @@ -37,7 +40,7 @@ class ApplicationRecord < ActiveRecord::Base end def validate_content_length(column) - max_length = column.type == :text ? 20_000 : 255 + max_length = column.type == :text ? MAX_TEXT_COLUMN_LENGTH : MAX_STRING_COLUMN_LENGTH return if self[column.name].nil? || self[column.name].length <= max_length errors.add(column.name.to_sym, "is too long (maximum is #{max_length} characters)") diff --git a/spec/builders/contact_inbox_with_contact_builder_spec.rb b/spec/builders/contact_inbox_with_contact_builder_spec.rb index 60f0834af..58502539f 100644 --- a/spec/builders/contact_inbox_with_contact_builder_spec.rb +++ b/spec/builders/contact_inbox_with_contact_builder_spec.rb @@ -39,6 +39,21 @@ describe ContactInboxWithContactBuilder do expect(contact_inbox.inbox_id).to eq(inbox.id) end + it 'truncates long contact names before creating the contact' do + long_name = 'a' * 300 + + contact_inbox = described_class.new( + source_id: '123456', + inbox: inbox, + contact_attributes: { + name: long_name, + email: 'testemail@example.com' + } + ).perform + + expect(contact_inbox.contact.name).to eq(long_name.first(ApplicationRecord::MAX_STRING_COLUMN_LENGTH)) + end + it 'doesnot create contact if it already exist with identifier' do contact_inbox = described_class.new( source_id: '123456',