instructure/canvas-lms · error · ImportError
Improper status "# " for institutional tag category #
Error message
Improper status "#{status}" for institutional tag category #{sis_id} What it means
Raised by SisImports::InstitutionalTagCategoryImporter#add_institutional_tag_category when status is non-blank but does not match /\A(active|deleted)/i. The importer accepts only 'active' or 'deleted' (case-insensitive) as lifecycle states; any other string is rejected before the record is created or updated.
Solutions
- Change the status value in the CSV/API call to exactly 'active' or 'deleted' (any casing).
- Add a mapping step in the export pipeline translating foreign status enums to Canvas's active/deleted vocabulary.
- Strip whitespace/extra text from the status field before import.
- Re-run the SIS import.
Example fix
// before
add_institutional_tag_category('cat-1', 'Department Tags', 'desc', 'inactive')
// after
add_institutional_tag_category('cat-1', 'Department Tags', 'desc', 'deleted') Defensive patterns
Strategy: validation
Validate before calling
status = status.to_s.strip.downcase
raise ArgumentError, "invalid status #{status}" unless %w[active deleted].include?(status)
add_institutional_tag_category(sis_id, name, description, status) Try / catch
begin
importer.add_institutional_tag_category(sis_id, name, description, status)
rescue SisImports::ImportError => e
Rails.logger.warn("Bad status for category #{sis_id}: #{e.message}")
end Prevention
- Normalize foreign status enums (enabled/disabled, A/I) to active/deleted in the exporter.
- Whitelist allowed values in a preprocessing step before import.
- Don't reuse status vocabularies from other SIS objects (courses/sections).
When it happens
Trigger: Calling add_institutional_tag_category with status like 'inactive', 'archived', 'enabled', or values with leading/trailing text that break the anchored match; CSV rows using vocabulary from a different SIS object (e.g. course 'unpublished'/'completed').
Common situations: Mapping an external system's status enum (enabled/disabled, A/I flags) straight into the Canvas SIS file; typos like 'actve' or 'deletd'; copying status values from course/section imports where the allowed set differs.
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
- An institutional tag category did not pass validation
- Improper grade_publishing_status "#
- Improper status "# " for an enrollment
- No account found for context
- No institutional_tag_id given for an institutional tag
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/ed28a84345c8a1f1.
Report an issue: GitHub.
Appendix: source
Thrown at lib/sis/institutional_tag_category_importer.rb:45
importer.success_count
end
class Work
attr_accessor :success_count, :roll_back_data
def initialize(batch, root_account, logger)
@batch = batch
@root_account = root_account
@logger = logger
@success_count = 0
@roll_back_data = []
end
def add_institutional_tag_category(sis_id, name, description, status)
raise ImportError, "No category_id given for an institutional tag category" if sis_id.blank?
raise ImportError, "No name given for institutional tag category #{sis_id}" if name.blank?
raise ImportError, "No status given for institutional tag category #{sis_id}" if status.blank?
raise ImportError, "Improper status \"#{status}\" for institutional tag category #{sis_id}" unless /\A(active|deleted)/i.match?(status)
return if @batch.skip_deletes? && /deleted/i.match?(status)
category = InstitutionalTagCategory.find_by(root_account_id: @root_account.id, sis_source_id: sis_id)
category ||= InstitutionalTagCategory.new(account: @root_account,
root_account: @root_account,
sis_source_id: sis_id)
category.name = name
category.description = description
category.sis_batch_id = @batch.id
category.workflow_state = /deleted/i.match?(status) ? "deleted" : "active"
if category.save
data = SisBatchRollBackData.build_data(sis_batch: @batch, context: category)
@roll_back_data << data if data
@success_count += 1
maybe_write_roll_back_data
elseView on GitHub (pinned to 1c9f0bb801)