instructure/canvas-lms · error · ImportError

# # didn't exist for # user

Error message

#{is_tags ? "Differentiation tag" : "Group"} #{group_id} didn't exist for #{is_tags ? "differentiation tag" : "group"} user

What it means

The importer looks up the group (or differentiation tag) by sis_source_id among the root account's groups/tags, including the in-memory groups_cache. If no group with that id exists, ImportError is raised because there is nothing to add the membership to.

Solutions

  1. Import groups.csv (or the tag definitions) before the membership rows
  2. Fix the group_id/tag_id so it matches the group's sis_source_id
  3. Verify the group exists under the same root account and was not deleted
  4. Ensure is_tags matches the id kind — tag ids must go through is_tags: true

Example fix

# before
membership references g_999 which was never in groups.csv
# after
add "g_999" row to groups.csv, import it, then memberships
Defensive patterns

Strategy: validation

Validate before calling

group = is_tags ? root_account.all_differentiation_tags.find_by(sis_source_id: gid)
               : root_account.all_groups.find_by(sis_source_id: gid)
raise "group #{gid} not found" unless group

Try / catch

begin
  importer.add_group_membership(uid, gid, status, is_tags: true)
rescue SIS::GroupImporter::ImportError => e
  raise unless e.message =~ /(Differentiation tag|Group) .* didn't exist/
  Rails.logger.warn("Unknown group #{gid}; skipping row")
end

Prevention

When it happens

Trigger: group_id / tag_id in the membership row does not match any existing group's sis_source_id under the root account; groups.csv not processed before memberships; group was deleted; id belongs to another root account or course not in scope.

Common situations: Out-of-order CSV processing (memberships before groups); typo in group id; group created in a subaccount not covered by all_groups scope; using tag ids against the non-tag path (is_tags mismatch).

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/f592b25fdbc62d6b. Report an issue: GitHub.

Appendix: source

Thrown at lib/sis/group_membership_importer.rb:60

      def add_group_membership(user_id, group_id, status, is_tags: false)
        user_id = user_id.to_s
        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

View on GitHub (pinned to 1c9f0bb801)