instructure/canvas-lms · error

publishing disallowed for this publishing user

Error message

publishing disallowed for this publishing user

What it means

Course#publish_final_grades raises this when the grade-export format requires a publishing pseudonym (an SIS-linked login for the publishing user) but SisPseudonym.for returns nil for that user in this course's root account. The format's :requires_publishing_pseudonym flag demands that the person posting grades be traceable to the SIS; without a pseudonym the publish is aborted.

Solutions

  1. Choose a publishing_user that has an active SIS pseudonym in the course's root account (verify via SisPseudonym.for(user, course)).
  2. Run a SIS import that provisions the user's login, or add sis_user_id to their pseudonym, then retry.
  3. Pick a grade export format that does not set requires_publishing_pseudonym, or remove that flag from the registered export type.
  4. Confirm the root_account_id/shard is correct so SisPseudonym lookup isn't hitting the wrong account.

Example fix

// before
Course.expire_all_bulk_course_publish_grades(course, admin)

// after
publishing_user = SisPseudonym.for(admin, course) ? admin : SisPseudonym.staff_with_pseudonym(course)
course.publish_final_grades(publishing_user)
Defensive patterns

Strategy: validation

Validate before calling

raise 'no SIS pseudonym' if SisPseudonym.for(publishing_user, course).nil?

Type guard

is_sis_user = ->(u, c) { !SisPseudonym.for(u, c).nil? }

Prevention

When it happens

Trigger: Calling publish_final_grades (or its async wrapper) with settings[:format_type] whose Course.valid_grade_export_types entry has requires_publishing_pseudonym: true, where the publishing_user has no SIS pseudonym in the root account (SisPseudonym.for(publishing_user, self) is nil).

Common situations: Admin without an SIS-imported login publishing grades; pseudonym soft-deleted or on the wrong shard/account; SIS integration not configured for the root account so no sis_pseudonyms exist; using a non-SIS user (e.g. a support admin) as the publishing user.

Related errors


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

Appendix: source

Thrown at app/models/course.rb:2646

    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 }

    posts_to_make.each do |enrollment_ids, res, mime_type, headers = {}|
      posted_enrollment_ids += enrollment_ids
      if res
        Canvas.timeout_protection("send_final_grades_to_endpoint:#{global_root_account_id}", timeout_options) do
          SSLCommon.post_data(settings[:publish_endpoint], res, mime_type, headers)
        end

View on GitHub (pinned to 1c9f0bb801)