instructure/canvas-lms · error · ImportError

No tag_set_id or course_id given for differentiation tag #

Error message

No tag_set_id or course_id given for differentiation tag #{tag_id}. At least one is required for new tags.

What it means

add_tag resolves the tag's context either from an explicit tag_set (tag_set_id) or from a course_id. If neither a tag_set nor a course_id was supplied and the tag referenced by tag_id cannot be found (so no context can be inferred), the importer raises because it has no context in which to create the new differentiation tag.

Solutions

  1. Add a course_id (or tag_set_id) to the SIS row so the tag has a context
  2. Correct the tag_id so it matches an existing tag whose context can be used
  3. If the import is API/console-driven, pass tag_set_id or course_id to add_tag
  4. Validate the CSV before upload: every new tag row must include at least one of tag_set_id or course_id

Example fix

# before (CSV row)
"tag_123,,New Tag"            # no tag_set_id, no course_id
# after
"tag_123,C123,New Tag"        # course_id supplied
Defensive patterns

Strategy: validation

Validate before calling

raise 'tag row needs tag_set_id or course_id' if tag_set_id.blank? && course_id.blank?
# or in CSV lint: require at least one of the two columns for every new tag_id

Try / catch

begin
  importer.add_tag(tag_id, name, tag_set_id: tsid, course_id: cid)
rescue SIS::GroupImporter::ImportError => e
  raise unless e.message =~ /No tag_set_id or course_id given/
  Rails.logger.error("Tag row missing context: #{e.message}")
end

Prevention

When it happens

Trigger: add_tag called with a tag_id that does not match an existing tag (so tag&.context is nil) and with neither tag_set_id nor course_id provided in the row.

Common situations: SIS CSV groups file for differentiation tags missing course_id column while using a new tag_id (creation attempt); typo in tag_id so the existing-tag lookup misses; importer invoked programmatically without context parameters.

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/84131e93cb57ed7e. Report an issue: GitHub.

Appendix: source

Thrown at lib/sis/group_importer.rb:228

        if tag_set_id.present?
          tag_set = find_category(tag_set_id, context, :differentiation_tag_category, "differentiation_tag", tag_id)
        end

        tag = @root_account.all_differentiation_tags.find_by(sis_source_id: tag_id)

        if tag_set
          context = tag_set.context
          raise ImportError, "Differentiation Tags are not enabled for Account #{context.account.id}." unless context.account.allow_assign_to_differentiation_tags?

          if tag
            tag.group_category = tag_set
          else
            tag = tag_set.groups.non_collaborative.new(name:, sis_source_id: tag_id)
          end
        end

        context ||= tag&.context
        raise ImportError, "No tag_set_id or course_id given for differentiation tag #{tag_id}. At least one is required for new tags." unless context

        can_change_context?(tag, context, "differentiation_tag", tag_id)

        tag ||= context.groups.new(name:, non_collaborative: true, sis_source_id: tag_id)
        tag.name = name if name.present? && !tag.stuck_sis_fields.include?(:name)
        tag.context = context
        tag.sis_batch_id = @batch.id
        tag.workflow_state = (status == "deleted") ? "deleted" : "available"

        # Ensure tag category context matches tag context
        if tag&.group_category &&
           tag.group_category.context_id != context.id &&
           tag.group_category.context_type == context.class_name
          tag.group_category.update!(context_id: context.id)
        else
          tag_set ||= context.differentiation_tag_categories.create!(name:, non_collaborative: true)
          # If adding as a single tag, have the tag set match the single tag status
          tag_set.destroy if status == "deleted"

View on GitHub (pinned to 1c9f0bb801)