{"record":{"id":"ed4a6f81543802fe","repo":"instructure/canvas-lms","slug":"no-user-id-given-for-a-is-tags-differentiation-tag-group","errorCode":null,"errorMessage":"No user_id given for a #{is_tags ? \"differentiation tag\" : \"group\"} user","messagePattern":"No user_id given for a #(.+?) user","errorType":"exception","errorClass":"ImportError","httpStatus":null,"severity":"error","filePath":"lib/sis/group_membership_importer.rb","lineNumber":47,"sourceCode":"    end\n\n    class Work\n      attr_accessor :success_count, :roll_back_data\n\n      def initialize(batch, root_account, logger)\n        @batch = batch\n        @root_account = root_account\n        @logger = logger\n        @success_count = 0\n        @groups_cache = {}\n        @roll_back_data = []\n      end\n\n      def add_group_membership(user_id, group_id, status, is_tags: false)\n        user_id = user_id.to_s\n        group_id = group_id.to_s\n        raise ImportError, \"No #{is_tags ? \"tag_id\" : \"group_id\"} given for a #{is_tags ? \"differentiation tag\" : \"group\"} user\" if group_id.blank?\n        raise ImportError, \"No user_id given for a #{is_tags ? \"differentiation tag\" : \"group\"} user\" if user_id.blank?\n        raise ImportError, \"Improper status \\\"#{status}\\\" for a #{is_tags ? \"differentiation tag\" : \"group\"} user\" unless /\\A(accepted|deleted)/i.match?(status)\n        return if @batch.skip_deletes? && status =~ /deleted/i\n\n        pseudo = @root_account.pseudonyms.find_by(sis_user_id: user_id)\n        user = pseudo&.user\n\n        group = @groups_cache[group_id]\n        scope = is_tags ? @root_account.all_differentiation_tags : @root_account.all_groups\n        group ||= scope.where(sis_source_id: group_id).preload(:context).take\n        @groups_cache[group.sis_source_id] = group if group\n\n        raise ImportError, \"User #{user_id} didn't exist for #{is_tags ? \"differentiation tag\" : \"group\"} user\" unless user\n        raise ImportError, \"#{is_tags ? \"Differentiation tag\" : \"Group\"} #{group_id} didn't exist for #{is_tags ? \"differentiation tag\" : \"group\"} user\" unless group\n\n        if group.context.is_a?(Course) && !group.context.all_real_users.where(id: user.id).exists?\n          raise ImportError, \"User #{user_id} doesn't have an enrollment in the course of #{is_tags ? \"differentiation tag\" : \"group\"} #{group_id}.\"\n        end\n","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/lib/sis/group_membership_importer.rb#L29-L65","documentation":"Validation guard in GroupMembershipImporter::Work#add_group_membership raised when the user_id argument is blank. Because user_id is matched by both group membership and differentiation tag ingestion, the message names the entity kind ('differentiation tag' vs 'group') based on the is_tags flag. It fires at row-parse time, before any user lookup.","triggerScenarios":"add_group_membership called with nil/empty user_id; CSV row missing the user_id (or user's SIS ID) column.","commonSituations":"CSV missing user_id cell; export pipeline produced empty user column; calling the importer API directly without the user argument; using canvas user id where sis_user_id is expected so lookup also fails downstream.","solutions":["Populate user_id (the SIS user id) in each membership row","Fix the upstream export to include the user's sis_user_id","Skip or fix malformed rows before submitting the SIS batch","Ensure you pass the user id, not an empty string, when calling add_group_membership directly"],"exampleFix":"# before\n\"\",g_456,accepted\n# after\n\"u_100,g_456,accepted\"","handlingStrategy":"validation","validationCode":"raise 'blank user_id' if row['user_id'].to_s.strip.empty?","typeGuard":null,"tryCatchPattern":"begin\n  importer.add_group_membership(uid, gid, status)\nrescue SIS::GroupImporter::ImportError => e\n  raise unless e.message =~ /No user_id given/\n  Rails.logger.error(\"Membership row missing user_id\")\nend","preventionTips":["Require user_id column on every row of group user CSVs","Fix upstream exports that drop empty user cells silently","Pre-import lint to reject rows with blank user ids"],"tags":["sis-import","groups","missing-argument","csv"],"backgroundTag":"missing-required-argument","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}