instructure/canvas-lms · error · ImportError

No user_id given for a user

Error message

No user_id given for a user

What it means

SisImporter#add_user validates each SIS::Models::User before batching it for import. The very first check requires a non-blank user_id (the SIS identifier used to match/create the user). If user.user_id is nil or empty, an SisImports::ImportError-style ImportError is raised immediately so the batch is never queued with an unidentifiable record.

Solutions

  1. Ensure the source record has a user_id before calling add_user: skip or fix rows with a blank user_id
  2. Verify your CSV/XML header or parser maps the id column to Models::User#user_id
  3. Default or derive user_id from a login/email upstream if the export truly lacks it
  4. Wrap add_user calls in error handling so one bad row can be logged and the import continued

Example fix

// before
sis_users.each { |u| importer.add_user(u) }
// after
sis_users.each do |u|
  next if u.user_id.blank?
  importer.add_user(u)
end
Defensive patterns

Strategy: validation

Validate before calling

raise 'user_id required' if user.respond_to?(:user_id) && user.user_id.blank?
importer.add_user(user) if user.user_id.present?

Type guard

def importable_user?(u)
  u.is_a?(Sis::Models::User) && u.user_id.present?
end

Try / catch

begin
  importer.add_user(user)
rescue SisImports::ImportError => e
  Rails.logger.warn("skipping user row: #{e.message}")
end

Prevention

When it happens

Trigger: Calling importer.add_user(user) with a SIS::Models::User built from a CSV/XML row whose user_id column (or <user_id> element) is blank; constructing Models::User manually and omitting user_id; a parser mapping that drops the user_id field.

Common situations: SIS export files with a missing/empty user_id cell; custom integration scripts building user rows by hand; schema drift after SIS export format changes leaving the id column unnamed.

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


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/0b702a3615c59a15. Report an issue: GitHub.

Appendix: source

Thrown at lib/sis/user_importer.rb:75

        @batch = batch
        @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)

View on GitHub (pinned to 1c9f0bb801)