From 1bcc25f95cf358a82b08bec4f5bdeddd4b30e3e9 Mon Sep 17 00:00:00 2001 From: Tanmay Deep Sharma Date: Mon, 4 May 2026 14:15:38 +0700 Subject: [PATCH] fix(voice): guard audio attachment after_create_commit hooks on file presence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both enqueue_audio_transcription and broadcast_message_update_for_audio fired immediately after Attachment#save without checking whether a file was actually attached. The broadcast path then walked through Message#push_event_data → Attachment#audio_metadata → file.metadata, which is nil when no file is attached, raising NoMethodError on file.metadata[:width]. This was visible to: - Captain::OpenAiMessageBuilderService specs that build audio attachments without a file (intentional — those specs test attachment_parts logic, not file storage). 4 specs failing, all crashing inside the broadcast callback rather than in the code under test. - Any future callsite that creates an audio attachment shell before attaching the blob (we don't have one in production today, but the callbacks should be defensive). Add `return unless file.attached?` to both. The transcription job has nothing to transcribe without a file; the broadcast carries no useful audio info before the file lands. The callbacks fire again — correctly — once the blob is attached and committed in a subsequent transaction. --- enterprise/app/models/enterprise/concerns/attachment.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/enterprise/app/models/enterprise/concerns/attachment.rb b/enterprise/app/models/enterprise/concerns/attachment.rb index 24cc338cd..06b8b641a 100644 --- a/enterprise/app/models/enterprise/concerns/attachment.rb +++ b/enterprise/app/models/enterprise/concerns/attachment.rb @@ -14,6 +14,7 @@ module Enterprise::Concerns::Attachment def enqueue_audio_transcription return unless file_type.to_sym == :audio + return unless file.attached? Messages::AudioTranscriptionJob.perform_later(id) end @@ -21,6 +22,10 @@ module Enterprise::Concerns::Attachment def broadcast_message_update_for_audio return unless file_type.to_sym == :audio return unless message + # Without an attached file, the message serializer's audio_metadata path + # dereferences `file.metadata[:width]` on nil and raises. The pre-attach + # broadcast wouldn't carry useful audio info anyway — skip until upload completes. + return unless file.attached? message.reload.send_update_event end