{"record":{"id":"104cdf14c7bf2f9d","repo":"instructure/canvas-lms","slug":"require-course","errorCode":null,"errorMessage":"require course","messagePattern":"require course","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/models/courses/timetable_event_builder.rb","lineNumber":27,"sourceCode":"# the terms of the GNU Affero General Public License as published by the Free\n# Software Foundation, version 3 of the License.\n#\n# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY\n# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\n# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more\n# details.\n#\n# You should have received a copy of the GNU Affero General Public License along\n# with this program. If not, see <http://www.gnu.org/licenses/>.\n\nmodule Courses\n  class TimetableEventBuilder\n    # builds calendar events for a course (or course sections) according to a timetable\n\n    attr_reader :course, :course_section, :event_context, :errors\n\n    def initialize(course: nil, course_section: nil)\n      raise \"require course\" unless course\n\n      @course = course\n      @course_section = course_section\n      @event_context = course_section || course\n    end\n\n    # generates individual events from a simplified \"timetable\" between the course/section start and end dates\n    # :weekdays - days of week (0-Sunday, 1-Monday, 2-Tuesday, 3-Wednesday, 4-Thursday, 5-Friday, 6-Saturday)\n    # :start_time - basically any time that can be parsed by the magic (e.g. \"11:30 am\")\n    # :end_time - ditto\n    # :location_name (optional)\n    def generate_event_hashes(timetable_hashes)\n      time_zone = course.time_zone\n      event_hashes = []\n      timetable_hashes.each do |timetable_hash|\n        course_start_at = timetable_hash[:course_start_at]\n        course_end_at = timetable_hash[:course_end_at]\n","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/courses/timetable_event_builder.rb#L9-L45","documentation":"Courses::TimetableEventBuilder#initialize requires a course: the builder generates calendar events scoped to a course (optionally a section), so constructing it without a course raises 'require course' immediately.","triggerScenarios":"Courses::TimetableEventBuilder.new(course_section: section) with course omitted; passing course: nil from a caller whose lookup failed; passing only course_section even though the builder keys on course.","commonSituations":"Timetable importers where the Course lookup by sis_id/name returned nil and the nil was forwarded; misuse assuming course_section alone suffices; refactors that renamed a local variable used as the course: argument.","solutions":["Resolve the Course and pass course: course to the builder.","Validate the course lookup succeeded before constructing the builder and surface a user-facing error if not.","If operating on a section only, still pass its course: builder.new(course: section.course, course_section: section)."],"exampleFix":"// before\nbuilder = TimetableEventBuilder.new(course_section: section)\n\n// after\nraise 'course not found' unless course\nbuilder = TimetableEventBuilder.new(course: course, course_section: section)","handlingStrategy":"type-guard","validationCode":"raise 'course not found' if course.nil?\nTimetableEventBuilder.new(course: course, course_section: section)","typeGuard":"def buildable?(course, section = nil)\n  course.is_a?(Course)\nend","tryCatchPattern":null,"preventionTips":["Fail early with a clear message when course lookup returns nil","Never rely on course_section alone; always resolve its course","Type-check constructor inputs in importer entry points"],"tags":["ruby-on-rails","timetables","constructor"],"backgroundTag":"missing-required-argument","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}