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

insufficient permission

Error message

insufficient permission

What it means

ensure_destroyed checks `@working_assignment.grants_right?(current_user, :delete)` unconditionally before destroying an assignment (deleteAssignment mutation). If the caller lacks :delete on the assignment, it raises 'insufficient permission' even if the assignment is already deleted.

Solutions

  1. Grant the user :delete right (e.g., teacher/enrollment with manage assignments permission) before calling deleteAssignment.
  2. Verify with `assignment.grants_right?(user, :delete)` in console before invoking.
  3. Check you're authenticated as the intended user (token owner).
  4. If testing, enroll a teacher or stub grants_right? accordingly.

Example fix

// before
mutation { deleteAssignment(input: { id }) } # as read-only user

// after: ensure caller can delete
user.enroll(course, 'TeacherEnrollment').accept!  # or verify
assignment.grants_right?(user, :delete) # true before calling mutation
Defensive patterns

Strategy: validation

Validate before calling

if (!assignment.permissions.delete) throw new Error('cannot delete assignment')

Try / catch

try {
  await deleteAssignment({ id })
} catch (e) {
  if (e.message === 'insufficient permission') showNoPermissionUi()
}

Prevention

When it happens

Trigger: Calling deleteAssignment as a user without delete rights on the assignment's course (e.g., teacher where course settings require manage rights, or a student); current_user nil due to unauthenticated token; permission check fails because the assignment belongs to a different course than assumed.

Common situations: Custom roles with delete withheld; API token scoped to a user with read-only access; sub-account admin without course-level delete; automation tokens whose user lost permissions after role changes.

Understand the failure class

Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at app/graphql/mutations/assignment_base.rb:308

    # now remove all _tags_ that are not required
    (current_module_ids - required_module_ids).to_set.each do |module_id_to_remove|
      # assignments can be part of multiple modules, so we have to search through all the tags
      # and if context_module_id is the module to remove, then we need to delete the tag
      content_tags.each do |tag|
        if tag.context_module_id == module_id_to_remove
          tag.destroy
        end
      end
    end

    # we need to reload the assignment so things get returned correctly
    @working_assignment.reload
  end

  def ensure_destroyed
    # check for permissions no matter what
    raise GraphQL::ExecutionError, "insufficient permission" unless @working_assignment.grants_right? current_user, :delete

    # if we are already destroyed, then dont do anything
    return if @working_assignment.workflow_state == "deleted"

    # actually destroy now.
    SubmissionLifecycleManager.with_executing_user(@current_user) do
      @working_assignment.destroy
    end
  end

  def ensure_restored
    # if we are already not destroyed, then dont do anything
    return if @working_assignment.workflow_state != "deleted"
    raise GraphQL::ExecutionError, "insufficient permission" unless @working_assignment.grants_right? current_user, :delete

    @working_assignment.restore
  end

View on GitHub (pinned to 1c9f0bb801)