instructure/canvas-lms · warning

Child content tag was not found for #

Error message

Child content tag was not found for #{self.class.name} #{id} - either this is from old code or something bad happened

What it means

MasterCourses::Restrictor#mark_downstream_changes records which columns changed on a locked master-course item by updating its child content tag. When no MasterCourses::ChildContentTag exists for the object, it logs this warning and skips tracking — either the item predates master-course locking code or a tag that should exist is missing.

Solutions

  1. Usually safe to ignore for legacy content: the change simply isn't tracked as a downstream change
  2. If sync tracking matters, re-run the master course association/tag migration to backfill missing child tags
  3. Verify the item belongs to a master template (check MasterCourses::MasterTemplate associations)
  4. Check for code deleting child tags and restore referential integrity
  5. master_courses_child_content_tags table

Example fix

// before
# silent warn on missing tag
Rails.logger.warn("Child content tag was not found ...")
// after
Rails.logger.warn("Child content tag was not found ...")
Canvas::Errors.capture(e_missing_tag, content_type: self.class.name, content_id: id) if template_content?
Defensive patterns

Strategy: fallback

Validate before calling

tag = MasterCourses::ChildContentTag.where(
  content_type: obj.class.name, content_id: obj.id
).first
puts('tag missing — change will not be synced') unless tag

Type guard

def blueprint_managed?(obj)
  MasterCourses::ChildContentTag.exists?(content: obj)
end

Try / catch

begin
  mark_downstream_changes(columns)
rescue => e
  Rails.logger.warn("downstream tracking failed: #{e.message}")
end

Prevention

When it happens

Trigger: An edit to a master-course (blueprint) locked object whose child content tag lookup returns nil — objects created before the blueprint feature existed, tags deleted, or unsaved/non-master-template content passing through the restrictor.

Common situations: Old courses retrofitted as blueprint courses (items have no child tags); direct console/data fixes that removed tags; edits to content not actually governed by a master template; race conditions during template migration.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at app/models/master_courses/restrictor.rb:175

      changed_columns.delete(state_column)
      changed_columns << "manually_deleted"
    end
    if changed_columns.any?
      tag_content = if is_a?(Assignment) && (submittable = submittable_object)
                      submittable # mark on the owner's tag
                    else
                      self
                    end
      MasterCourses::ChildContentTag.transaction do
        child_tag = MasterCourses::ChildContentTag.where(content: tag_content).lock.first
        if child_tag
          new_changes = changed_columns - child_tag.downstream_changes
          if new_changes.any?
            child_tag.downstream_changes += new_changes
            child_tag.save!
          end
        else
          Rails.logger.warn("Child content tag was not found for #{self.class.name} #{id} - either this is from old code or something bad happened")
        end
      end
    end
  end

  def create_child_content_tag
    # i thought about making this a bulk insert at the end of the migration but the race conditions seemed scary
    if @importing_migration && is_child_content?
      @importing_migration.master_course_subscription.content_tag_for(self)
    end
  end

  def check_before_overwriting_child_content_on_import
    return unless @importing_migration && is_child_content?

    child_tag = @importing_migration.master_course_subscription.content_tag_for(self) # find or create it
    return unless child_tag && child_tag.downstream_changes.present?

View on GitHub (pinned to 1c9f0bb801)