{"record":{"id":"0ba39a6363660ae5","repo":"instructure/canvas-lms","slug":"user-errors-first-join-user-user-row-user-id-login-user-row","errorCode":null,"errorMessage":"#{user.errors.first.join(\" \")} (user #{user_row.user_id}, login #{user_row.login_id})","messagePattern":"#(.+?) \\(user #(.+?), login #(.+?)\\)","errorType":"validation","errorClass":"ImportError","httpStatus":null,"severity":"error","filePath":"lib/sis/user_importer.rb","lineNumber":345,"sourceCode":"          pseudo.sis_ssha = user_row.ssha_password unless user_row.ssha_password.blank?\n          pseudo.reset_persistence_token if pseudo.sis_ssha_changed? && pseudo.password_auto_generated\n          user_touched = false\n\n          user.sortable_name_explicitly_set = true if user_row.sortable_name.present?\n\n          begin\n            User.transaction(requires_new: true) do\n              sticky_opts = user.sis_stickiness_options\n              if user.changed? || (sticky_opts[:override_sis_stickiness] && sticky_opts[:clear_sis_stickiness] &&\n                 user[\"stuck_sis_fields\"].present?)\n                user_touched = true\n                user_changed = user.changed?\n                user_saved = user.save\n                # need to call save first so we can get the user id\n                record_sync_for(user) if user_saved && user_changed\n                if !user_saved && !user.errors.empty?\n                  message = generate_user_warning(user.errors.first.join(\" \"), user_row.user_id, user_row.login_id)\n                  raise ImportError, message\n                end\n              elsif @batch\n                @users_to_set_sis_batch_ids << user.id\n              end\n              pseudo.user_id = user.id\n              if pseudo.changed?\n                pseudo.sis_batch_id = @batch.id if @batch\n                if pseudo.save_without_broadcasting\n                  record_sync_for(user)\n                  p_data = SisBatchRollBackData.build_data(sis_batch: @batch, context: pseudo)\n                  @roll_back_data << p_data if p_data\n                elsif !pseudo.errors.empty?\n                  message = generate_user_warning(pseudo.errors.first.full_message, user_row.user_id, user_row.login_id)\n                  raise ImportError, message\n                end\n              end\n            end\n          rescue ImportError","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/lib/sis/user_importer.rb#L327-L363","documentation":"SisImports::ImportError raised in SIS::UserImporter#process_batch when user.save fails ActiveRecord validation. The first validation error message is formatted with the row's sis user_id and login_id via generate_user_warning, then raised so the whole row is recorded as a batch error.","triggerScenarios":"During process_batch (invoked from add_user), an existing or new User fails validation on save — e.g. name exceeding length limits, invalid characters in name fields, or any User model validation failure. The importer reads user.errors.first and aborts the row.","commonSituations":"CSV names longer than the users.name column limit (255 chars); names containing only whitespace or invalid characters after the importer's parsing; invalid email/other column data bleeding into user attributes; locale/config changes that tighten validations between imports.","solutions":["Read the validation message embedded in the error (before the '(user X, login Y)' suffix) to see which attribute failed","Shorten or correct the offending CSV field (typically full_name/sortable_name) and re-run the import","Strip whitespace/control characters from name columns in the source data","If a validation was recently added/tightened, fix existing records or adjust the constraint"],"exampleFix":"// before (users.csv)\nuser_id,full_name\n1001,<255+ character name string...>\n\n// after\nuser_id,full_name\n1001,Reasonably Short Name","handlingStrategy":"try-catch","validationCode":"if user.name.to_s.strip.length > 255\n  raise 'full_name exceeds 255 chars'\nend","typeGuard":null,"tryCatchPattern":"begin\n  importer.add_user(row)\nrescue SisImports::ImportError => e\n  if e.message =~ /^(.+) \\(user (.+), login (.+)\\)$/\n    logger.warn(\"User validation failed for sis_id=#{$2}: #{$1}\")\n  else\n    raise\n  end\nend","preventionTips":["Cap name fields at the DB column length (255) when generating CSVs","Strip control/whitespace characters from name columns","Dry-run imports in a test account before production"],"tags":["sis-import","activerecord-validation","ruby","user-model"],"backgroundTag":"schema-validation-failed","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"}