{"record":{"id":"c623a7d1b5953ebe","repo":"instructure/canvas-lms","slug":"no-user-id-given-for-an-enrollment","errorCode":null,"errorMessage":"No user_id given for an enrollment","messagePattern":"No user_id given for an enrollment","errorType":"exception","errorClass":"ImportError","httpStatus":null,"severity":"error","filePath":"lib/sis/enrollment_importer.rb","lineNumber":134,"sourceCode":"        @users_to_touch_ids = Set.new\n        @courses_to_touch_ids = Set.new\n        @courses_to_recache_due_dates = {}\n        @enrollments_to_add_to_favorites = []\n        @enrollments_to_update_sis_batch_ids = []\n        @roll_back_data = []\n        @enrollments_to_delete = []\n        @account_chain_cache = {}\n        @course = @section = nil\n        @course_roles_by_account_id = {}\n\n        @enrollment_batch = []\n        @success_count = 0\n      end\n\n      # Pass a single instance of SIS::Models::Enrollment\n      def add_enrollment(enrollment)\n        raise ImportError, \"No course_id or section_id given for an enrollment\" unless enrollment.valid_context?\n        raise ImportError, \"No user_id given for an enrollment\" unless enrollment.valid_user?\n        raise ImportError, \"Improper status \\\"#{enrollment.status}\\\" for an enrollment\" unless enrollment.valid_status?\n        return if @batch.skip_deletes? && enrollment.status =~ /deleted/i\n\n        @enrollment_batch << enrollment\n        process_batch if @enrollment_batch.size >= BATCH_SIZE\n      end\n\n      def any_left_to_process?\n        !@enrollment_batch.empty?\n      end\n\n      def process_batch\n        return unless any_left_to_process?\n\n        enrollment_info = nil\n        until @enrollment_batch.empty?\n          enrollment_info = @enrollment_batch.shift\n","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/lib/sis/enrollment_importer.rb#L116-L152","documentation":"Validation guard raised by SisImports::Errors when add_enrollment is called with a blank user_id on the SIS::Models::Enrollment row. It fires during SIS enrollment CSV ingestion before any database lookup, aborting the batch (or row batch) because an enrollment cannot be attached to a user without an identifier.","triggerScenarios":"Calling `add_enrollment(enrollment)` with an Enrollment whose user_id is nil/blank; an enrollments CSV row missing the user_id column; a user_id referencing a user that produced no lookup value during parsing.","commonSituations":"CSV exported with a different user column name (e.g. login instead of user_id); rows for users deleted from the source system; scripts building Enrollment objects without setting user_id.","solutions":["Ensure each enrollments CSV row includes a valid user_id (SIS user id)","Fix column headers/mapping so user_id is parsed into the model","For programmatic use, pass `user_id:` when constructing the Enrollment"],"exampleFix":"// before\nSIS::Models::Enrollment.new(course_id: 'c1', user_id: nil, status: 'active')\n// after\nSIS::Models::Enrollment.new(course_id: 'c1', user_id: 'u1', status: 'active')","handlingStrategy":"validation","validationCode":"raise 'missing user_id' if enrollment.user_id.blank?","typeGuard":"def has_user?(enrollment)\n  enrollment.user_id.present?\nend","tryCatchPattern":"begin\n  importer.add_enrollment(enrollment)\nrescue SIS::Base::ImportError => e\n  logger.warn(\"Skipping enrollment: #{e.message}\")\nend","preventionTips":["Always map the user identifier column to user_id","Trim and normalize user ids during preprocessing","Cross-check user ids against the users CSV before the enrollments import"],"tags":["ruby","sis-import","enrollment","missing-identifier"],"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"}