instructure/canvas-lms · error · ImportError

No new_id or new_integration_id given for change_sis_id

Error message

No new_id or new_integration_id given for change_sis_id

What it means

process_change_sis_id raises this when both new_id and new_integration_id are blank. A change_sis_id entry exists to set a new SIS or integration identifier; with neither present there is nothing to write, so the row is rejected before any lookup.

Solutions

  1. Supply new_id with the desired new SIS identifier.
  2. Or supply new_integration_id (use the literal <delete> to clear integration_id).
  3. If the goal is removing an SIS id, use the standard SIS CSV delete mechanism instead of change_sis_id.

Example fix

// before
user,old-sis-id,
// after
user,old-sis-id,new-sis-id
Defensive patterns

Strategy: validation

Validate before calling

if dc.new_id.blank? && dc.new_integration_id.blank?
  raise ArgumentError, 'new_id or new_integration_id required'
end
process_change_sis_id(dc)

Try / catch

begin
  process_change_sis_id(dc)
rescue SIS::ImportError => e
  logger.warn("no-op row dropped: #{e.message}")
end

Prevention

When it happens

Trigger: A change_sis_id row where new_id is empty AND new_integration_id is empty (e.g. only old_id supplied), such as a delete-style row submitted through the change endpoint.

Common situations: Attempting to 'clear' a SIS id by leaving new_id blank (unsupported — deletions go through the sis CSV delete path), or column-shifted CSV rows where new_id fell into the wrong column.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at lib/sis/change_sis_id_importer.rb:70

    class Work
      attr_accessor :success_count,
                    :things_to_update_batch_ids,
                    :users_to_sync

      def initialize(batch, root_account, logger)
        @batch = batch
        @root_account = root_account
        @logger = logger
        @success_count = 0
        @things_to_update_batch_ids = {}
        @users_to_sync = Set.new
      end

      def process_change_sis_id(data_change)
        raise ImportError, "No type given for change_sis_id" if data_change.type.blank?
        raise ImportError, "No old_id or old_integration_id given for change_sis_id" if data_change.old_id.blank? && data_change.old_integration_id.blank?
        raise ImportError, "No new_id or new_integration_id given for change_sis_id" if data_change.new_id.blank? && data_change.new_integration_id.blank?

        type = data_change.type.downcase.strip
        things_to_update_batch_ids[type] ||= Set.new

        types = {
          "user" => { scope: @root_account.pseudonyms, column: :sis_user_id },
          "course" => { scope: @root_account.all_courses },
          "section" => { scope: @root_account.course_sections },
          "term" => { scope: @root_account.enrollment_terms },
          "account" => { scope: @root_account.all_accounts },
          "group" => { scope: @root_account.all_groups },
          "group_category" => { scope: @root_account.all_group_categories },
        }

        details = types[type]
        raise ImportError, "Invalid type '#{type}' for change_sis_id" unless details

        column = details[:column] || :sis_source_id

View on GitHub (pinned to 1c9f0bb801)