instructure/canvas-lms · error

can't accept

Error message

can't accept

What it means

Enrollment#accept! is the strict/banging wrapper around #accept: it calls accept and raises 'can't accept' when accept returns a falsy result, i.e. the enrollment could not be transitioned to an accepted/invited-accepted state under current rules (wrong workflow state, enrollment not invitable/accept-able, etc.).

Solutions

  1. Check the enrollment state first and only call accept! when acceptance is allowed (e.g. invited?/invited_state?)
  2. Use the non-banging enrollment.accept and handle the false return instead of raising
  3. Reload the enrollment before accepting to pick up concurrent state changes
  4. Pass accept(force: true) via the underlying method only when you intentionally need to override constraints

Example fix

// before
enrollment.accept!
// after
enrollment.reload
enrollment.accept if enrollment.invited?
Defensive patterns

Strategy: try-catch

Validate before calling

enrollment.reload
raise 'not acceptable' unless enrollment.may_accept? # or check invited state
enrollment.accept!

Try / catch

begin
  enrollment.accept!
rescue RuntimeError => e
  raise unless e.message == "can't accept"
  Rails.logger.warn("enrollment #{enrollment.id} not acceptable (#{enrollment.workflow_state})")
end

Prevention

When it happens

Trigger: Calling enrollment.accept! when #accept returns false/nil — typically because the enrollment's workflow_state does not permit acceptance (e.g. already rejected/completed/deleted, not invited), or the user on the enrollment is not the one being accepted for without force.

Common situations: Self-enrollment or invitation-accept flows hitting a stale enrollment that was already rejected or deleted in another tab; background jobs accepting enrollments after the course concluded; specs accepting a factory-built enrollment that was never in invited state.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at app/models/enrollment.rb:751

    STATE_RANK_HASH[state.to_s]
  end

  STATE_BY_DATE_RANK = ["active", %w[invited creation_pending pending_active pending_invited], "completed", "inactive", "rejected", "deleted"].freeze
  STATE_BY_DATE_RANK_HASH = rank_hash(STATE_BY_DATE_RANK)
  def self.state_by_date_rank_sql
    @state_by_date_rank_sql ||= Arel.sql(
      rank_sql(STATE_BY_DATE_RANK, "enrollment_states.state")
        .sub(/^CASE/, "CASE WHEN enrollment_states.restricted_access THEN #{STATE_BY_DATE_RANK.index("inactive")}") # pretend restricted access is the same as inactive
    )
  end

  def state_with_date_sortable
    STATE_RANK_HASH[state_based_on_date.to_s]
  end

  def accept!
    res = accept
    raise "can't accept" unless res

    res
  end

  def accept(force: false)
    GuardRail.activate(:primary) do
      return false unless force || invited?

      if update_attribute(:workflow_state, "active")
        if type == "StudentEnrollment"
          Enrollment.recompute_final_score_in_singleton(user_id, course_id)
        end
        true
      end
    end
  end

  def reset_notifications_cache

View on GitHub (pinned to 1c9f0bb801)