{"record":{"id":"6dc3622b810dfd14","repo":"instructure/canvas-lms","slug":"insufficient-permissions-delete-conversations","errorCode":null,"errorMessage":"Insufficient permissions","messagePattern":"Insufficient permissions","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/delete_conversations.rb","lineNumber":31,"sourceCode":"# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\n# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more\n# details.\n#\n# You should have received a copy of the GNU Affero General Public License along\n# with this program. If not, see <http://www.gnu.org/licenses/>.\n#\n\nclass Mutations::DeleteConversations < Mutations::BaseMutation\n  graphql_name \"DeleteConversations\"\n\n  # input arguments\n  argument :ids, [ID], required: true, prepare: GraphQLHelpers.relay_or_legacy_ids_prepare_func(\"Conversation\")\n\n  field :conversation_ids, [ID], null: true\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    errors = {}\n    context[:deleted_models] = { conversations: {} }\n    # rubocop:disable Style/BlockDelimiters\n    resolved_ids = input[:ids].filter_map { |id|\n      conversation = Conversation.find_by(id:)\n      if conversation.nil?\n        errors[id] = \"Unable to find Conversation\"\n        next\n      end\n\n      participant_record = current_user.all_conversations.find_by(conversation_id: conversation.id)\n      if participant_record.nil?\n        errors[id] = \"Insufficient permissions\"\n        next\n      end\n","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/delete_conversations.rb#L13-L49","documentation":"GraphQL::ExecutionError raised at the top of Mutations::DeleteConversations#resolve when the current_user's account root has the restrict_student_access feature flag enabled. In that mode students are not permitted to delete conversations through this mutation.","triggerScenarios":"Calling deleteConversations while the root account feature restrict_student_access is enabled for the current user's account context.","commonSituations":"Institutions that enabled restrict_student_access to limit student messaging actions; test environments with the flag turned on; students hitting the error after their school changed feature settings.","solutions":["Confirm the feature flag state: root_account.feature_enabled?(:restrict_student_access)","Disable the flag if the institution intends to allow student conversation deletion","Use an account admin user or admin API endpoint to delete conversations","Surface a friendly UI message instead of calling the mutation for flagged students"],"exampleFix":"// before\n# student calls mutation with flag on -> 'Insufficient permissions'\nif account.root_account.feature_enabled?(:restrict_student_access)\n  hideDeleteUI()\nend\n// after\ndef canDeleteConversations?(user)\n  !user.account.root_account.feature_enabled?(:restrict_student_access) || user.admin?\nend","handlingStrategy":"validation","validationCode":"if (rootAccount.featureEnabled('restrict_student_access') && !user.isAdmin) hideDeleteConversations()","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Gate UI affordances on the restrict_student_access flag","Test mutations in environments with the flag enabled","Provide admins an alternate deletion path"],"tags":["graphql","feature-flag","permissions"],"backgroundTag":"insufficient-permissions","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"}