{"record":{"id":"23cdd73353c948bc","repo":"instructure/canvas-lms","slug":"insufficient-permissions-delete-discussion-topic","errorCode":null,"errorMessage":"Insufficient permissions","messagePattern":"Insufficient permissions","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"warning","filePath":"app/graphql/mutations/delete_discussion_topic.rb","lineNumber":33,"sourceCode":"# 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#\nclass Mutations::DeleteDiscussionTopic < Mutations::BaseMutation\n  graphql_name \"DeleteDiscussionTopic\"\n  # input arguments\n  argument :id, ID, required: true, prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func(\"DiscussionTopic\")\n\n  # the return data if the delete is successful\n  field :discussion_topic_id, ID, null: false\n\n  def resolve(input:)\n    record = DiscussionTopic.active.find_by(id: input[:id])\n    raise GraphQL::ExecutionError, \"Unable to find Discussion Topic\" if record.nil? || !record.grants_right?(current_user, nil, :read)\n\n    unless record.grants_right?(current_user, nil, :delete)\n      raise GraphQL::ExecutionError, \"Insufficient permissions\"\n    end\n\n    context[:deleted_models] = { discussion_topic: {} }\n    context[:deleted_models][:discussion_topic] = record\n    record.destroy\n    {\n      discussion_topic_id: record.id\n    }\n  end\n\n  def self.discussion_topic_id_log_entry(_topic, context)\n    context[:deleted_models][:discussion_topic]\n  end\nend\n","sourceCodeStart":15,"sourceCodeEnd":48,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/delete_discussion_topic.rb#L15-L48","documentation":"This GraphQL mutation raises \"Insufficient permissions\" when the current user does not have the :delete right on the target DiscussionTopic. The record is found and readable (it passed the earlier find/read check), but delete authorization fails via grants_right?. This is Canvas's permission model enforcing that only users with delete rights (e.g. teachers, admins) can destroy a discussion topic.","triggerScenarios":"Calling the deleteDiscussionTopic mutation with a valid, readable topic id while the current_user lacks :delete on that topic's context — e.g. a student calling it on a course discussion, or a teacher on a topic in a course where they only have TA/read rights.","commonSituations":"Scripts using a non-admin token, users enrolled read-only in a course, topics locked to student deletion, or cross-course authorization confusion where the caller assumed course-level rights apply.","solutions":["Verify the current_user grants_right?(topic.context, :delete) before calling the mutation","Use an account admin token or a user with teacher role in the topic's course","Check enrollment roles/permissions in the course admin UI","Confirm the mutation is passed the correct topic id for the intended course"],"exampleFix":"// before\nrecord.destroy # raises if user lacks :delete\n// after\nunless record.grants_right?(current_user, nil, :delete)\n  raise GraphQL::ExecutionError, \"Insufficient permissions\"\nend\nrecord.destroy","handlingStrategy":"try-catch","validationCode":"// caller-side pre-check via a GraphQL query\nconst perms = await query(topicPermissions, { id });\nif (!perms?.delete) throw new SkipMutation();","typeGuard":"function canDeleteTopic(topic) {\n  return topic != null && topic.permissions?.delete === true;\n}","tryCatchPattern":"try {\n  await client.mutate(DELETE_DISCUSSION_TOPIC, { id });\n} catch (e) {\n  if (e.message === \"Insufficient permissions\") {\n    notifyUser(\"You do not have permission to delete this discussion topic.\");\n  } else throw e;\n}","preventionTips":["Query permissions fields on the topic type before showing delete UI","Ensure test tokens have the intended course roles","Check grants_right?(:delete) in rails console when debugging","Hide delete controls for read-only enrollments"],"tags":["graphql","authorization","permissions","discussion-topic"],"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"}