instructure/canvas-lms · error · ImportError
No type given for change_sis_id
Error message
No type given for change_sis_id
What it means
SIS::ChangeSisIdImporter::Work#process_change_sis_id raises this ImportError when the SIS change-sis-id row has a blank `type`. The type selects which AR scope/column mapping (user, course, section, term, account, group, group_category) to use, so without it no lookup can even be attempted. It is a hard fail-fast guard at the top of the method.
Solutions
- Populate the type column with one of: user, course, section, term, account, group, group_category.
- Fix the CSV header so the parser maps the correct column into data_change.type.
- Filter out blank/short rows before yielding to process_change_sis_id.
Example fix
// before type,,old_id,U1,new_id,U2 // after type,old_id,new_id user,U1,U2
Defensive patterns
Strategy: validation
Validate before calling
raise ArgumentError, 'type required' if data_change.type.blank? process_change_sis_id(data_change)
Type guard
def valid_type?(dc) %w[user course section term account group group_category].include?(dc.type.to_s.downcase.strip) end
Try / catch
begin
process_change_sis_id(dc)
rescue SIS::ImportError => e
logger.warn("skipped row: #{e.message}")
errors << e.message
end Prevention
- Validate CSV headers against the documented change_sis_id schema before import.
- Skip or reject blank/short rows at parse time.
- Unit-test your CSV generator with a row-level schema check.
When it happens
Trigger: A change_sis_id CSV/attr row (e.g. SIS CSV 'change_sis_id' file or batch data_change) where the type column is empty/whitespace: data_change.type is nil or ''. Raised before any DB lookup.
Common situations: CSV rows with a missing or misnamed 'type' column (header typo like 'object_type'), rows generated by external scripts that omit type, or trailing blank lines parsed as data rows.
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
- No user_id given for a user
- A new_id, '# ', referenced an existing # and the # with #…
- A new_integration_id, '#
- A student referenced a non-existent user #
- An old_id, '# ', referenced a different # than the…
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/78d1fd56e31ae5ea.
Report an issue: GitHub.
Appendix: source
Thrown at lib/sis/change_sis_id_importer.rb:68
scope.update_all(sis_batch_id: @batch.id, updated_at: Time.now.utc)
end
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 detailsView on GitHub (pinned to 1c9f0bb801)