instructure/canvas-lms · error

endpoint undefined

Error message

endpoint undefined

What it means

When publishing final grades, the grade_export plugin settings must include a publish_endpoint URL; if settings[:publish_endpoint] is blank, this error stops publishing because there is no SIS endpoint to post to.

Solutions

  1. Set publish_endpoint in the grade_export plugin settings to the SIS grades URL
  2. Check settings[:publish_endpoint].present? before invoking publishing
  3. Verify plugin settings persist correctly in the target environment (DB vs YAML)

Example fix

// before
plugin.settings # publish_endpoint: nil
// after
plugin_settings['publish_endpoint'] = 'https://sis.example.com/grades'
plugin.save_settings
Defensive patterns

Strategy: validation

Validate before calling

plugin = Canvas::Plugin.find!('grade_export')
raise 'publish_endpoint not configured' if plugin.enabled? && plugin.settings[:publish_endpoint].blank?

Type guard

null

Try / catch

begin
  course.publish_final_grades(user)
rescue RuntimeError => e
  raise unless e.message == 'endpoint undefined'
  # guide admin to plugin settings to set the SIS endpoint
end

Prevention

When it happens

Trigger: grade_export plugin enabled but its publish_endpoint setting is empty/blank when publish_final_grades runs (via its worker).

Common situations: Plugin enabled during setup but endpoint URL never configured; endpoint cleared during maintenance; copying plugin settings between environments without the endpoint.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at app/models/course.rb:2639

  def send_final_grades_to_endpoint(publishing_user, user_ids_to_publish = nil)
    # actual grade publishing logic is here, but you probably want
    # 'publish_final_grades'

    recompute_student_scores_without_send_later(user_ids_to_publish)
    enrollments = student_enrollments.not_fake.eager_load(:user).preload(:course_section).order_by_sortable_name
    enrollments = enrollments.where(user_id: user_ids_to_publish) if user_ids_to_publish

    errors = []
    posts_to_make = []
    posted_enrollment_ids = []
    all_enrollment_ids = enrollments.map(&:id)

    begin
      raise "final grade publishing disabled" unless Canvas::Plugin.find!("grade_export").enabled?

      settings = Canvas::Plugin.find!("grade_export").settings
      raise "endpoint undefined" if settings[:publish_endpoint].blank?

      format_settings = Course.valid_grade_export_types[settings[:format_type]]
      raise "unknown format type: #{settings[:format_type]}" unless format_settings
      raise "grade publishing requires a grading standard" if !grading_standard_enabled? && format_settings[:requires_grading_standard]

      publishing_pseudonym = SisPseudonym.for(publishing_user, self)
      raise "publishing disallowed for this publishing user" if publishing_pseudonym.nil? && format_settings[:requires_publishing_pseudonym]

      callback = Course.valid_grade_export_types[settings[:format_type]][:callback]
      posts_to_make = callback.call(self, enrollments, publishing_user, publishing_pseudonym)
    rescue => e
      Enrollment.where(id: all_enrollment_ids).update_all(grade_publishing_status: "error", grade_publishing_message: e.to_s)
      raise e
    end

    default_timeout = Setting.get("send_final_grades_to_endpoint_timelimit", 15.seconds.to_s).to_f

    timeout_options = { raise_on_timeout: true, fallback_timeout_length: default_timeout }

View on GitHub (pinned to 1c9f0bb801)