instructure/canvas-lms · error · ImportError
No login_id given for user #
Error message
No login_id given for user #{user.user_id} What it means
add_user requires a non-blank login_id for every user being imported; the login is the credential users sign in with and is key to matching existing logins. After user_id passes, a blank login_id raises ImportError naming the offending user_id so the row can be located in the source file.
Solutions
- Populate login_id (usually the institutional email) on every user record before add_user
- Pre-filter rows with blank login_id and report them as source-data errors
- Check that your CSV/XML parser maps the login/email column to login_id (not a differently named field)
- Use add_user_to_login or a login-only path only when a login genuinely exists
Example fix
// before importer.add_user(Sis::Models::User.new(user_id: row['user_id'], status: row['status'])) // after importer.add_user(Sis::Models::User.new(user_id: row['user_id'], login_id: row['login_id'] || row['email'], status: row['status']))
Defensive patterns
Strategy: validation
Validate before calling
next unless user.login_id.present? importer.add_user(user)
Type guard
def has_login?(u) u.is_a?(Sis::Models::User) && u.login_id.present? end
Try / catch
begin
importer.add_user(user)
rescue SisImports::ImportError => e
errors << { user_id: user.user_id, reason: e.message }
end Prevention
- Fall back to email when login_id is blank, per your data policy
- Reject bad rows at parse time and surface them in the import report
- Assert login_id presence in tests with fixture rows lacking it
When it happens
Trigger: add_user(user) where user.login_id is nil/empty — typically a CSV row missing the login_id (email) column, or a Models::User constructed without one; also hit when login_only: true imports only carry an existing_* id but still must supply a login.
Common situations: SIS exports where the email/login column is blank for some users; scripts that populate only user_id and status; column-rename in the source system after an upgrade.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- No abstract_course_id given for an abstract course
- No existing user provided for login with SIS ID
- No long_name given for abstract course #
- No short_name given for abstract course #
- No status given for user #
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/9dabefd2bf6ebbef.
Report an issue: GitHub.
Appendix: source
Thrown at lib/sis/user_importer.rb:76
@root_account = root_account
@logger = logger
@batched_users = []
@messages = messages
@success_count = 0
@roll_back_data = []
@users_to_set_sis_batch_ids = []
@pseudos_to_set_sis_batch_ids = []
@users_to_add_account_associations = []
@users_to_update_account_associations = []
@users_to_sync = Set.new
@authentication_providers = {}
end
# Pass a single instance of SIS::Models::User
def add_user(user, login_only: false)
raise ImportError, "No user_id given for a user" if user.user_id.blank?
raise ImportError, "No login_id given for user #{user.user_id}" if user.login_id.blank?
raise ImportError, "No status given for user #{user.user_id}" if user.status.blank?
raise ImportError, "Improper status for user #{user.user_id}" unless user.status.match?(/\A(active|suspended|deleted)/i)
return if @batch.skip_deletes? && user.status.match?(/deleted/i)
if login_only && user.existing_user_id.blank? && user.existing_integration_id.blank? && user.existing_canvas_user_id.blank?
raise ImportError, I18n.t("No existing user provided for login with SIS ID %{user_id}", user_id: user.user_id)
end
@batched_users << user
process_batch(login_only:) if @batched_users.size >= BATCH_SIZE
end
def any_left_to_process?
!@batched_users.empty?
end
def infer_user_name(user_row, prior_name = nil)
if user_row.full_name.present?View on GitHub (pinned to 1c9f0bb801)