instructure/canvas-lms · error
Course required
Error message
Course required
What it means
CourseSection#infer_defaults sets root_account_id and derives section names/sis defaults from the parent course; it requires the course association to be set and raises 'Course required' otherwise. Called from before_validation/before_save during section creation.
Solutions
- Assign section.course = the Course (or course_id) before saving so infer_defaults has its parent.
- Build sections via course.course_sections.create instead of standalone CourseSection.new.
- Reorder code so the course association is set before any save/validation runs.
Example fix
// before section = CourseSection.new(name: 'Section A') section.save! // after section = course.course_sections.new(name: 'Section A') section.save!
Defensive patterns
Strategy: type-guard
Validate before calling
raise 'course missing' unless section.course || section.course_id
Type guard
def section_has_course?(section) section.course.present? || section.course_id.present? end
Prevention
- Always build sections via course.course_sections.new/create
- Validate imported rows have a resolvable course before instantiation
- Assign course before any save triggers callbacks
When it happens
Trigger: Creating or saving a CourseSection without assigning section.course = course first; bulk-importing sections without linking them to a course; SIS import code paths that build sections detached from their course.
Common situations: Hand-constructed CourseSection.new(...) in scripts/console missing the course; order-of-operations bug where course is assigned after validation triggers; importers creating sections per row but forgetting the FK on malformed rows.
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
- Course pace is deleted
- Course pace is not deleted
- invalid association
- invalid options - # (must be in # )
- Invalid section ids
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/22d7a6724acbf23d.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/course_section.rb:244
return true if !root_account_id_changed? && !integration_id_changed?
scope = root_account.course_sections.where(integration_id:)
scope = scope.where("id<>?", self) unless new_record?
return true unless scope.exists?
errors.add(:integration_id, t("integration_id_taken", "INTEGRATION ID \"%{integration_id}\" is already in use", integration_id:))
throw :abort
end
alias_method :parent_event_context, :course
def section_code
name
end
def infer_defaults
raise "Course required" unless course
self.root_account_id = course.root_account_id || Account.default.id
# This is messy, and I hate it.
# The SIS import actually gives us three names for a section
# and I don't know which one is best, or which one to show.
# Here's the current plan:
# - otherwise, just use name
# - use the method display_name to consolidate this logic
self.name ||= course.name if default_section
self.name ||= "#{course.name} #{Time.zone.today}"
end
def defined_by_sis?
!!sis_source_id
end
# NOTE: Don't assume the section_name contains the course name
# it might include it if the SIS specifies, but you shouldn'tView on GitHub (pinned to 1c9f0bb801)