instructure/canvas-lms · error · ImportError
Improper status "# " for a cross-listing
Error message
Improper status "#{status}" for a cross-listing What it means
The SIS cross-listing importer validates that each row's status is exactly 'active' or 'deleted' (case-insensitive) and raises ImportError for anything else. The status drives whether the section is cross-listed into the target course or uncross-listed, so unknown values are rejected before any data is touched.
Solutions
- Use only 'active' or 'deleted' as status values in the crosslist SIS file
- Strip whitespace and normalize casing of the status column before import
- Map third-party status vocabulary to active/deleted before calling add_crosslist
- Add a pre-import CSV lint that rejects rows with statuses outside the allowed set
Example fix
# before xlist.add_crosslist(course_id, section_id, row['status']) # "remove" # after status = row['status'].to_s.strip.downcase status = 'deleted' if status == 'remove' xlist.add_crosslist(course_id, section_id, status)
Defensive patterns
Strategy: validation
Validate before calling
unless status.to_s.match?(/\A(active|deleted)\z/i)
raise ArgumentError, "status must be active or deleted, got #{status.inspect}"
end Try / catch
begin
xlist.add_crosslist(xlist_course_id, section_id, status)
rescue SIS::ImportError => e
Rails.logger.warn("Bad crosslist status: #{e.message}")
end Prevention
- Whitelist statuses to active/deleted at the CSV parsing layer
- Normalize casing/whitespace before calling add_crosslist
- Map upstream SIS status vocabulary explicitly
- Add a lint step for crosslist.csv in CI
When it happens
Trigger: Calling add_crosslist(xlist_course_id, section_id, status) where status is not /\A(active|deleted)\z/i — e.g. 'delete', 'Active ', 'enabled', or a nil status from a blank CSV cell. Note the second guard at line 121 also catches statuses that pass initial regex checks only if the regex changed; normally this fires for unexpected case values hitting the case statement.
Common situations: Hand-edited SIS CSVs using synonyms like 'remove' or 'deactivate'; integrations sending boolean-ish values ('true'/'false'); locale-transformed exports; trailing whitespace or BOM characters contaminating the status column.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- A cross-listing referenced a non-existent section #
- A deleted cross-listing failed: #
- An active cross-listing failed: #
- Improper status # for a cross-listing
- No section_id given for a cross-listing
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/582f0f3531879d8a.
Report an issue: GitHub.
Appendix: source
Thrown at lib/sis/xlist_importer.rb:55
end
class Work
attr_accessor :success_count, :course_ids_to_update_associations
def initialize(batch, root_account, logger)
@batch = batch
@root_account = root_account
@logger = logger
@success_count = 0
@course = nil
@course_ids_to_update_associations = [].to_set
end
def add_crosslist(xlist_course_id, section_id, status)
raise ImportError, "No xlist_course_id given for a cross-listing" if xlist_course_id.blank?
raise ImportError, "No section_id given for a cross-listing" if section_id.blank?
raise ImportError, "Improper status \"#{status}\" for a cross-listing" unless /\A(active|deleted)\z/i.match?(status)
return if @batch.skip_deletes? && status =~ /deleted/i
section = @root_account.course_sections.find_by(sis_source_id: section_id)
raise ImportError, "A cross-listing referenced a non-existent section #{section_id}" unless section
unless @course && @course.sis_source_id == xlist_course_id
@course = @root_account.all_courses.find_by(sis_source_id: xlist_course_id)
if !@course && status =~ /\Aactive\z/i
# no course with this crosslist id found, make a new course,
# using the section's current course as a template
@course = Course.new
@course.root_account = @root_account
@course.account_id = section.course.account_id
@course.name = section.course.name
@course.course_code = section.course.course_code
@course.enrollment_term_id = section.course.enrollment_term_id
@course.start_at = section.course.start_at
@course.conclude_at = section.course.conclude_atView on GitHub (pinned to 1c9f0bb801)