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

Unauthorized

Error message

Unauthorized

What it means

Raised when the enrollment found by uuid does not belong to the current user (enrollment.user != current_user). The mutation only lets the invited user reject their own invitation, preventing users from rejecting others' enrollments.

Solutions

  1. Log in as the user the enrollment belongs to before rejecting
  2. Match the invitation email's target account (check email address vs active session)
  3. If an admin must reject, use the enrollments admin API instead of this user-scoped mutation
  4. Verify enrollment.user_id == current_user.id before calling

Example fix

// before
rejectEnrollmentInvitation(forwardedUuid) // session user != invitee
// after
if (enrollment.userId === currentUser.id) {
  rejectEnrollmentInvitation(enrollment.uuid)
}
Defensive patterns

Strategy: validation

Validate before calling

if (enrollment.userId !== currentUser.id) {
  show('This invitation belongs to a different account — log in as ' + enrollment.userEmail)
  return
}

Type guard

function isOwnEnrollment(enrollment, user) { return Boolean(user) && enrollment.userId === user.id }

Try / catch

try {
  await rejectEnrollmentInvitation({ enrollmentUuid })
} catch (e) {
  if (e.message.includes('Unauthorized')) show('Log in with the account the invitation was sent to')
  else throw e
}

Prevention

When it happens

Trigger: A logged-in user submits a rejection for someone else's enrollment uuid; shared/forwarded invitation link opened by another account; admin or observer attempting the mutation on behalf of a student.

Common situations: Multiple accounts logged in across browser profiles; forwarding the invitation email to a colleague who is already logged into their own Canvas account; automation using a service account token.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

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

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

module Mutations
  class RejectEnrollmentInvitation < BaseMutation
    argument :enrollment_uuid, String, required: true

    field :enrollment, Types::EnrollmentType, null: true
    field :success, Boolean, null: false

    def resolve(input:, **)
      user = context[:current_user]
      raise GraphQL::ExecutionError, I18n.t("Must be logged in") unless user

      enrollment = Enrollment.where(uuid: input[:enrollment_uuid]).first
      raise GraphQL::ExecutionError, I18n.t("Enrollment invitation not found") unless enrollment

      # Verify the enrollment belongs to the current user
      raise GraphQL::ExecutionError, I18n.t("Unauthorized") unless enrollment.user == user

      # Verify the enrollment is in invited state
      raise GraphQL::ExecutionError, I18n.t("Enrollment is not in invited state") unless enrollment.invited?

      begin
        if enrollment.reject
          {
            enrollment:,
            success: true
          }
        else
          {
            enrollment: nil,
            success: false,
            errors: [{ message: I18n.t("Failed to reject enrollment invitation") }]
          }
        end
      rescue => e

View on GitHub (pinned to 1c9f0bb801)