instructure/canvas-lms · error · ImportError

Group categories should not have integration IDs.

Error message

Group categories should not have integration IDs.

What it means

check_for_conflicting_ids raises this when type is 'group_category' and either old_integration_id or new_integration_id is present. GroupCategory models in Canvas have no integration_id column, so integration-ID based lookups/writes are meaningless and rejected outright.

Solutions

  1. Remove the integration_id values from the group_category row; identify the record via old_id and change it via new_id only.
  2. If an integration_id is genuinely needed, change the type to a supported entity (e.g. group) or add integration_id support upstream.
  3. Strip integration_id columns for group_category rows in the CSV generator.

Example fix

// before
type,old_id,new_id,old_integration_id
group_category,GC1,GC2,INT1
// after
type,old_id,new_id
group_category,GC1,GC2
Defensive patterns

Strategy: validation

Validate before calling

if dc.type.to_s.downcase.strip == 'group_category' &&
   (dc.old_integration_id.present? || dc.new_integration_id.present?)
  raise ArgumentError, 'group_category rows must not carry integration ids'
end
process_change_sis_id(dc)

Try / catch

begin
  process_change_sis_id(dc)
rescue SIS::ImportError => e
  errors << e.message
end

Prevention

When it happens

Trigger: A change_sis_id row with type=group_category whose old_integration_id or new_integration_id column is non-empty.

Common situations: One-size-fits-all SIS export scripts that always emit integration_id columns regardless of type, or copy-pasted rows where a group row's integration id was reused for a group_category.

Related errors


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

Appendix: source

Thrown at lib/sis/change_sis_id_importer.rb:124

      end

      def ids_to_change(column, data_change)
        updates = {}
        if data_change.new_id.present?
          updates[column] = data_change.new_id
        end
        if data_change.new_integration_id.present?
          updates["integration_id"] = data_change.new_integration_id
          if data_change.new_integration_id == "<delete>"
            updates["integration_id"] = nil
          end
        end
        updates
      end

      def check_for_conflicting_ids(column, details, type, data_change)
        if type == "group_category" && (data_change.old_integration_id || data_change.new_integration_id)
          raise ImportError, "Group categories should not have integration IDs."
        end

        check_new = details[:scope].where(column => data_change.new_id).exists? if data_change.new_id.present?
        raise ImportError, "A new_id, '#{data_change.new_id}', referenced an existing #{type} and the #{type} with #{column} '#{data_change.old_id}' was not updated" if check_new

        check_int = details[:scope].where(integration_id: data_change.new_integration_id).exists? if data_change.new_integration_id.present?
        raise ImportError, "A new_integration_id, '#{data_change.new_integration_id}', referenced an existing #{type} and the #{type} with integration_id '#{data_change.old_integration_id}' was not updated" if check_int
      end

      def find_item_to_update(column, details, type, data_change)
        if data_change.old_id.present?
          old_item = details[:scope].find_by(column => data_change.old_id)
        end
        if data_change.old_integration_id.present?
          old_int_item = details[:scope].find_by(integration_id: data_change.old_integration_id)
        end
        if data_change.old_id.present? && data_change.old_integration_id.present?
          raise ImportError, "An old_id, '#{data_change.old_id}', referenced a different #{type} than the old_integration_id, '#{data_change.old_integration_id}'" unless old_item == old_int_item

View on GitHub (pinned to 1c9f0bb801)