{"record":{"id":"16b7d5ec84b52e23","repo":"instructure/canvas-lms","slug":"all-conversationmessages-must-exist-within-the-same","errorCode":null,"errorMessage":"All ConversationMessages must exist within the same Conversation","messagePattern":"All ConversationMessages must exist within the same Conversation","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/delete_conversation_messages.rb","lineNumber":36,"sourceCode":"# with this program. If not, see <http://www.gnu.org/licenses/>.\n#\n\nclass Mutations::DeleteConversationMessages < Mutations::BaseMutation\n  graphql_name \"DeleteConversationMessages\"\n\n  # input arguments\n  argument :ids, [ID], required: true, prepare: GraphQLHelpers.relay_or_legacy_ids_prepare_func(\"ConversationMessage\")\n\n  field :conversation_message_ids, [ID], null: false\n\n  def resolve(input:)\n    if current_user.account.root_account.feature_enabled?(:restrict_student_access)\n      raise GraphQL::ExecutionError, \"Insufficient permissions\"\n    end\n\n    messages = ConversationMessage.preload(:conversation).find(input[:ids])\n    if messages.map(&:conversation).uniq.length > 1\n      raise GraphQL::ExecutionError, \"All ConversationMessages must exist within the same Conversation\"\n    end\n\n    participant_record = current_user.all_conversations.find_by(conversation_id: messages.first.conversation.id)\n    raise GraphQL::ExecutionError, \"Insufficient permissions\" if participant_record.nil?\n\n    participant_record.remove_messages(*messages)\n    context[:deleted_models] = { conversation_messages: {} }\n    messages.each { |message| context[:deleted_models][:conversation_messages][message.id.to_s] = message }\n    { conversation_message_ids: input[:ids] }\n  rescue ActiveRecord::RecordInvalid => e\n    errors_for(e.record)\n  rescue ActiveRecord::RecordNotFound\n    raise GraphQL::ExecutionError, \"Unable to find ConversationMessage\"\n  end\n\n  def self.conversation_message_ids_log_entry(entry, context)\n    context[:deleted_models][:conversation_messages][entry]\n  end","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/delete_conversation_messages.rb#L18-L54","documentation":"GraphQL::ExecutionError raised in Mutations::DeleteConversationMessages#resolve when the supplied message ids belong to more than one Conversation. The mutation only supports deleting messages within a single conversation, so it validates that all preloaded messages map to one conversation before checking participant permissions.","triggerScenarios":"Calling deleteConversationMessages with input[:ids] where messages.map(&:conversation).uniq.length > 1 — i.e. mixing message ids from two or more different conversations in one request.","commonSituations":"Client UIs that let users select messages across conversation threads before deleting; batch scripts reusing id lists; stale selections in the UI after conversations were merged or the user switched threads.","solutions":["Group ids by conversation and issue one mutation call per conversation","Validate client-side that all selected ids come from the same conversation before invoking the mutation","Fetch messages first and check conversation_id uniformity before calling the mutation","Use the batch_conversation_messages delete API if cross-conversation deletion is needed"],"exampleFix":"// before\ndeleteConversationMessages(ids: [101, 202, 303]) // ids span 2 conversations\n// after\nawait deleteConversationMessages(ids: [101, 202])\nawait deleteConversationMessages(ids: [303])","handlingStrategy":"validation","validationCode":"const convIds = new Set(ids.map(id => getMessage(id).conversationId))\nif (convIds.size > 1) throw new Error('ids must belong to one conversation')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Group ids by conversation before batching","Constrain multi-select UI to a single conversation thread","Refresh selection state after any conversation change"],"tags":["graphql","mutation","validation"],"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"}