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

Enrollment invitation not found

Error message

Enrollment invitation not found

What it means

AcceptEnrollmentInvitation looks up the enrollment by the provided enrollment_uuid (Enrollment.where(uuid: input[:enrollment_uuid]).first) and raises 'Enrollment invitation not found' when no enrollment matches. The uuid is a per-invitation identifier, so any typo, stale link, or deleted/merged enrollment leads here.

Solutions

  1. Verify the exact enrollment_uuid string from the invitation (no truncation/whitespace) and retry.
  2. Re-issue the invitation so a fresh enrollment/uuid is generated, then accept that.
  3. Confirm you are hitting the same environment/shard where the enrollment was created.
  4. Check the enrollment still exists: find by uuid in the Rails console (Enrollment.find_by(uuid: ...)).
  5. Handle nil in client code and surface 'invitation no longer valid' to the user with a path to re-invite.

Example fix

// before
const enrollment = await Enrollment.findOne({ where: { uuid: suppliedUuid } })
if (!enrollment) throw new Error("Enrollment invitation not found")
// after
const enrollment = await Enrollment.findOne({ where: { uuid: normalizeUuid(suppliedUuid) } })
if (!enrollment) return { success: false, reason: "invitation_invalid_or_expired" } // re-invite flow
Defensive patterns

Strategy: validation

Validate before calling

// validate uuid shape and presence before the call
const UUID_RE = /^[0-9a-f]{32}$/i // Canvas uuids (adjust per format)
if (!UUID_RE.test((enrollmentUuid || "").trim()))
  throw new Error("invalid enrollment_uuid; copy it from the invitation link exactly")

Try / catch

try {
  await client.request(ACCEPT_INVITATION, { enrollmentUuid })
} catch (e) {
  if (/Enrollment invitation not found/.test(e.message))
    return showInvitationExpiredScreen() // offer re-invite
  throw e
}

Prevention

When it happens

Trigger: Mutation called with an enrollment_uuid that does not exist: truncated/copy-paste-damaged uuid from an invitation email, invitation revoked and enrollment deleted, uuid from a different shard/ENV, or a fabricated id.

Common situations: Users clicking old invitation emails after the course was concluded and enrollments purged; test fixtures reusing uuids across environments (test vs production DB); self-registration tools storing uuids before enrollment creation completes.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at app/graphql/mutations/accept_enrollment_invitation.rb:33

# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#

module Mutations
  class AcceptEnrollmentInvitation < 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.accept!
          {
            enrollment:,
            success: true
          }
        else
          {
            enrollment: nil,
            success: false,
            errors: [{ message: I18n.t("Failed to accept enrollment invitation") }]

View on GitHub (pinned to 1c9f0bb801)