{"record":{"id":"6efcc1951a9a1b61","repo":"instructure/canvas-lms","slug":"unable-to-find-conversationmessage","errorCode":null,"errorMessage":"Unable to find ConversationMessage","messagePattern":"Unable to find ConversationMessage","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/delete_conversation_messages.rb","lineNumber":49,"sourceCode":"      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\nend\n","sourceCodeStart":31,"sourceCodeEnd":56,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/delete_conversation_messages.rb#L31-L56","documentation":"GraphQL::ExecutionError raised in the rescue ActiveRecord::RecordNotFound branch of Mutations::DeleteConversationMessages#resolve. It fires when ConversationMessage.preload(:conversation).find(input[:ids]) cannot find one of the requested ids (deleted, wrong shard, or never existed).","triggerScenarios":"Passing an id of a nonexistent, soft-deleted, or wrong-shard ConversationMessage in input[:ids]; ActiveRecord::RecordNotFound from find is translated to this message.","commonSituations":"Clients caching message ids after the message was deleted elsewhere; legacy numeric ids not converted to relay global ids; cross-shard lookups resolving on the wrong shard.","solutions":["Verify the message ids exist (ConversationMessage.exists?) before calling the mutation","Refresh stale client state after deletes instead of reusing cached ids","Ensure ids are passed as valid relay/legacy ids per the argument's prepare function","Check you are operating on the correct shard/root account"],"exampleFix":"// before\ndeleteConversationMessages(ids: [\"99999\"]) // already deleted\n// after\nconst ids = cachedIds.filter(id => messageExists(id))\ndeleteConversationMessages(ids)","handlingStrategy":"validation","validationCode":"const missing = ids.filter(id => !messageExists(id))\nif (missing.length) throw new Error(`Unknown message ids: ${missing}`)","typeGuard":null,"tryCatchPattern":"try {\n  await deleteConversationMessages(ids)\n} catch (e) {\n  if (/Unable to find ConversationMessage/.test(e.message)) await refreshMessages()\n}","preventionTips":["Purge cached ids after deletion","Refresh lists before batch operations","Handle RecordNotFound as idempotent success where safe"],"tags":["graphql","not-found","activerecord"],"backgroundTag":"record-not-found","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"}