instructure/canvas-lms · error · GraphQL::ExecutionError

All ConversationMessages must exist within the same…

Error message

All ConversationMessages must exist within the same Conversation

What it means

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.

Solutions

  1. Group ids by conversation and issue one mutation call per conversation
  2. Validate client-side that all selected ids come from the same conversation before invoking the mutation
  3. Fetch messages first and check conversation_id uniformity before calling the mutation
  4. Use the batch_conversation_messages delete API if cross-conversation deletion is needed

Example fix

// before
deleteConversationMessages(ids: [101, 202, 303]) // ids span 2 conversations
// after
await deleteConversationMessages(ids: [101, 202])
await deleteConversationMessages(ids: [303])
Defensive patterns

Strategy: validation

Validate before calling

const convIds = new Set(ids.map(id => getMessage(id).conversationId))
if (convIds.size > 1) throw new Error('ids must belong to one conversation')

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/16b7d5ec84b52e23. Report an issue: GitHub.

Appendix: source

Thrown at app/graphql/mutations/delete_conversation_messages.rb:36

# with this program. If not, see <http://www.gnu.org/licenses/>.
#

class Mutations::DeleteConversationMessages < Mutations::BaseMutation
  graphql_name "DeleteConversationMessages"

  # input arguments
  argument :ids, [ID], required: true, prepare: GraphQLHelpers.relay_or_legacy_ids_prepare_func("ConversationMessage")

  field :conversation_message_ids, [ID], null: false

  def resolve(input:)
    if current_user.account.root_account.feature_enabled?(:restrict_student_access)
      raise GraphQL::ExecutionError, "Insufficient permissions"
    end

    messages = ConversationMessage.preload(:conversation).find(input[:ids])
    if messages.map(&:conversation).uniq.length > 1
      raise GraphQL::ExecutionError, "All ConversationMessages must exist within the same Conversation"
    end

    participant_record = current_user.all_conversations.find_by(conversation_id: messages.first.conversation.id)
    raise GraphQL::ExecutionError, "Insufficient permissions" if participant_record.nil?

    participant_record.remove_messages(*messages)
    context[:deleted_models] = { conversation_messages: {} }
    messages.each { |message| context[:deleted_models][:conversation_messages][message.id.to_s] = message }
    { conversation_message_ids: input[:ids] }
  rescue ActiveRecord::RecordInvalid => e
    errors_for(e.record)
  rescue ActiveRecord::RecordNotFound
    raise GraphQL::ExecutionError, "Unable to find ConversationMessage"
  end

  def self.conversation_message_ids_log_entry(entry, context)
    context[:deleted_models][:conversation_messages][entry]
  end

View on GitHub (pinned to 1c9f0bb801)