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
- Import/create the user's course enrollment before the group membership row
- Remove the membership row for users not enrolled in the course
- Verify enrollment sis data is up to date and the user is a 'real' (non-deleted, non-temp) user
- 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
- Import enrollments before group memberships in every batch
- Reconcile drops: remove membership rows for users who un-enrolled
- Verify enrollment data is current as of the import date
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
- A # user did not pass validation (user: # , # : # , error…
- Improper status "# " for an enrollment
- Improper status "# " for a # user
- # # didn't exist for # user
- No course_id or section_id given for an enrollment
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)