instructure/canvas-lms · error · ImportError

User # doesn't have an enrollment in the course of # # .

Error message

User #{user_id} doesn't have an enrollment in the course of #{is_tags ? "differentiation tag" : "group"} #{group_id}.

What it means

When the group/tag's context is a Course, the importer verifies the user has an enrollment in that course (all_real_users) before attaching membership. A user without an enrollment raises ImportError, since differentiation tags and course groups only make sense for enrolled users.

Solutions

  1. Import/create the user's course enrollment before the group membership row
  2. Remove the membership row for users not enrolled in the course
  3. Verify enrollment sis data is up to date and the user is a 'real' (non-deleted, non-temp) user
  4. Re-run the import after enrollments have been processed

Example fix

# before (no enrollment row for u_100 in C123)
u_100,tag_C123_1,accepted
# after
first import enrollments.csv with u_100 in C123, then the membership row
Defensive patterns

Strategy: validation

Validate before calling

if group.context.is_a?(Course) && !group.context.all_real_users.where(id: user.id).exists?
  raise "user #{user.id} lacks enrollment in #{group.context.id}"
end

Try / catch

begin
  importer.add_group_membership(uid, gid, status)
rescue SIS::GroupImporter::ImportError => e
  raise unless e.message =~ /doesn't have an enrollment in the course/
  Rails.logger.warn("User #{uid} not enrolled; deferring row until enrollments import")
end

Prevention

When it happens

Trigger: Membership row pairs a user with a course-scoped group/tag whose course the user is not (or no longer) enrolled in; user's enrollment was deleted before this import; group moved to a different course after memberships were authored.

Common situations: Enrollments CSV processed after group memberships; user dropped the course between export and import; tag assigned to a course section user never enrolled in; sis batch ordering problems.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at lib/sis/group_membership_importer.rb:63

        group_id = group_id.to_s
        raise ImportError, "No #{is_tags ? "tag_id" : "group_id"} given for a #{is_tags ? "differentiation tag" : "group"} user" if group_id.blank?
        raise ImportError, "No user_id given for a #{is_tags ? "differentiation tag" : "group"} user" if user_id.blank?
        raise ImportError, "Improper status \"#{status}\" for a #{is_tags ? "differentiation tag" : "group"} user" unless /\A(accepted|deleted)/i.match?(status)
        return if @batch.skip_deletes? && status =~ /deleted/i

        pseudo = @root_account.pseudonyms.find_by(sis_user_id: user_id)
        user = pseudo&.user

        group = @groups_cache[group_id]
        scope = is_tags ? @root_account.all_differentiation_tags : @root_account.all_groups
        group ||= scope.where(sis_source_id: group_id).preload(:context).take
        @groups_cache[group.sis_source_id] = group if group

        raise ImportError, "User #{user_id} didn't exist for #{is_tags ? "differentiation tag" : "group"} user" unless user
        raise ImportError, "#{is_tags ? "Differentiation tag" : "Group"} #{group_id} didn't exist for #{is_tags ? "differentiation tag" : "group"} user" unless group

        if group.context.is_a?(Course) && !group.context.all_real_users.where(id: user.id).exists?
          raise ImportError, "User #{user_id} doesn't have an enrollment in the course of #{is_tags ? "differentiation tag" : "group"} #{group_id}."
        end

        if group && is_tags
          raise ImportError, "Differentiation Tags are not enabled for Account #{group.context.account.id}." unless group.context.account.allow_assign_to_differentiation_tags?
        end

        # can't query group.group_memberships, since that excludes deleted memberships
        group_membership = GroupMembership.where(group_id: group, user_id: user)
                                          .order(Arel.sql("CASE WHEN workflow_state = 'accepted' THEN 0 ELSE 1 END")).take
        group_membership ||= group.group_memberships.build(user:)

        group_membership.sis_batch_id = @batch.id

        case status
        when /accepted/i
          group_membership.workflow_state = "accepted"
        when /deleted/i
          group_membership.workflow_state = "deleted"

View on GitHub (pinned to 1c9f0bb801)