{"record":{"id":"73f17ac0becfe5f4","repo":"instructure/canvas-lms","slug":"can-only-forward-one-conversation-at-a-time","errorCode":null,"errorMessage":"can only forward one conversation at a time","messagePattern":"can only forward one conversation at a time","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/models/conversation.rb","lineNumber":355,"sourceCode":"\n  def self.build_message(current_user, body, options = {})\n    message = ConversationMessage.new\n    message.author_id = current_user.id\n    message.body = body\n    message.generated = options[:generated] || false\n    message.automated = options[:automated] || false\n    if options[:root_account_id]\n      message.context_type = \"Account\"\n      message.context_id = options[:root_account_id]\n    end\n\n    message.asset = options[:asset]\n    message.attachment_ids = options[:attachment_ids] if options[:attachment_ids].present?\n    message.media_comment = options[:media_comment] if options[:media_comment].present?\n    if options[:forwarded_message_ids].present?\n      messages = ConversationMessage.where(id: options[:forwarded_message_ids].map(&:to_i))\n      conversation_ids = messages.select(&:forwardable?).map(&:conversation_id).uniq\n      raise \"can only forward one conversation at a time\" if conversation_ids.size != 1\n      raise \"user doesn't have permission to forward these messages\" unless current_user.all_conversations.where(conversation_id: conversation_ids.first).exists?\n\n      # TODO: optimize me\n      message.forwarded_message_ids = messages.map(&:id).join(\",\")\n    end\n\n    # Grab snapshot hash of user's inbox settings and save to message (If FF is enabled)\n    if Account.site_admin.feature_enabled?(:inbox_settings)\n      message.inbox_settings_ooo_hash = Inbox::InboxService.inbox_settings_ooo_hash(user_id: current_user.id, root_account_id: options[:root_account_id])\n    end\n\n    message\n  end\n\n  def preload_users_and_context_codes\n    users = User.where(id: conversation_participants.map(&:user_id)).pluck(:id, :updated_at).map do |id, updated_at|\n      User.send(:instantiate, \"id\" => id, \"updated_at\" => updated_at)\n    end","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/conversation.rb#L337-L373","documentation":"Conversation#add_message (and forwarding flow) validates forwarded messages come from exactly one conversation. After filtering to forwardable messages, if the resulting distinct conversation_ids count is not 1, this error is raised to prevent mixing messages from multiple conversations in one forward.","triggerScenarios":"Calling Conversation#add_message with options[:forwarded_message_ids] containing messages from more than one conversation, or IDs that resolve to zero forwardable messages (conversation_ids.size == 0).","commonSituations":"UI code letting users multi-select messages across conversations then forwarding them together; stale/expired message IDs that are no longer forwardable so the filtered set is empty; passing raw arrays of mixed IDs from a client.","solutions":["Ensure the forwarded message IDs all belong to a single conversation before calling add_message","Filter the selection in the UI so multi-conversation selections are forwarded in separate calls","Check messages are forwardable? first; if none are, skip forwarding instead of passing empty/mixed IDs"],"exampleFix":"// before\nconversation.add_message(user, 'fyi', forwarded_message_ids: [1, 2, 77])\n// after\nids = [1, 2] # all from conversation 42\nconversation.add_message(user, 'fyi', forwarded_message_ids: ids)\n# forward messages from conversation 77 in a separate call","handlingStrategy":"validation","validationCode":"ids = forwarded_message_ids.map(&:to_i)\nconvs = ConversationMessage.where(id: ids).select(&:forwardable?).map(&:conversation_id).uniq\nraise ArgumentError, 'forward messages from exactly one conversation' unless convs.size == 1","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Restrict multi-select forwarding in the UI to a single conversation","Validate message ownership/conversation before queuing forwards","Handle empty forwardable sets without calling add_message"],"tags":["ruby","rails","conversations","forwarding"],"backgroundTag":"invalid-argument-value","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}