instructure/canvas-lms · error · PeerReview::CourseNotFoundError

Course does not exist

Error message

Course does not exist

What it means

PeerReview::CourseNotFoundError raised by validate_course_exists when the Course object is nil/not present. Nearly every peer review service depends on a valid course to scope lookups and permissions.

Solutions

  1. Load the course via Course.find/courses scoped to the correct shard and confirm it exists
  2. Parse the context id correctly (strip 'course_' prefix) before lookup
  3. Check the course was not deleted and the API consumer uses a valid course id

Example fix

// before
course = Course.find_by(id: 'course_123'.to_i) # nil -> raises
// after
course = Course.active.find(context_id.sub(/\Acourse_/, ''))
service.call(course: course)
Defensive patterns

Strategy: type-guard

Validate before calling

course = Course.find_by(id: course_id)
raise ArgumentError, 'course not found' unless course

Type guard

course = context.is_a?(Course) ? context : Course.find_by(id: context.to_s.sub(/\Acourse_/, '').to_i)

Try / catch

begin
  service.call(course:)
rescue PeerReview::CourseNotFoundError
  head :not_found
end

Prevention

When it happens

Trigger: Calling any peer review service with a course id that resolves to nil: nonexistent course id, course on another shard, deleted course, or lookup without the proper account/rootscope.

Common situations: Using the wrong id field (course.id vs context id 'course_123'); multi-shard lookup not going through the correct shard; course deleted before the job runs.

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/502f28f86994930e. Report an issue: GitHub.

Appendix: source

Thrown at app/services/peer_review/validations.rb:211

  def validate_set_type_required(set_type)
    raise PeerReview::SetTypeRequiredError, I18n.t("Set type is required") unless set_type.present?
  end

  def validate_set_id_required(set_id)
    raise PeerReview::SetIdRequiredError, I18n.t("Set id is required") unless set_id.present?
  end

  def validate_override_exists(override)
    raise PeerReview::OverrideNotFoundError, I18n.t("Override does not exist") unless override.present?
  end

  def validate_section_exists(section)
    raise PeerReview::SectionNotFoundError, I18n.t("Section does not exist") unless section.present?
  end

  def validate_course_exists(course)
    raise PeerReview::CourseNotFoundError, I18n.t("Course does not exist") unless course.present?
  end

  def validate_student_ids_required(student_ids)
    if student_ids.nil? || student_ids == "" || student_ids.to_s.strip.empty? || (student_ids.is_a?(Array) && student_ids.empty?)
      raise PeerReview::StudentIdsRequiredError, I18n.t("Student ids are required")
    end
  end

  def validate_student_ids_in_course(student_ids)
    raise PeerReview::StudentIdsNotInCourseError, I18n.t("Student ids are not in course") if student_ids.blank?
  end

  def validate_set_type_supported(set_type, services)
    unless services.key?(set_type)
      supported_types = services.keys.join(", ")
      raise PeerReview::SetTypeNotSupportedError,
            I18n.t("Set type '%{set_type}' is not supported. Supported types are: %{supported_types}", set_type:, supported_types:)
    end

View on GitHub (pinned to 1c9f0bb801)