instructure/canvas-lms · error
cannot call enrollment_state on a new record
Error message
cannot call enrollment_state on a new record
What it means
Enrollment#enrollment_state overrides the enrollment_state association reader and refuses to run on unsaved records, because the EnrollmentState row is derived from persisted enrollment data; reading it for a new_record? would be meaningless. create_enrollment_state and other code must therefore only call this on persisted enrollments.
Solutions
- Save the enrollment before reading enrollment_state
- Guard with return if enrollment.new_record? before accessing enrollment_state
- Use enrollment_state_overrides/computed state helpers that work on unsaved records if you need predicted state
- In specs, create! the enrollment instead of building it
Example fix
// before state = enrollment.enrollment_state # raises for new record // after state = enrollment.new_record? ? nil : enrollment.enrollment_state
Defensive patterns
Strategy: type-guard
Validate before calling
next if enrollment.new_record? state = enrollment.enrollment_state
Type guard
def persisted_enrollment?(enrollment) enrollment.is_a?(Enrollment) && !enrollment.new_record? end
Try / catch
begin state = enrollment.enrollment_state rescue RuntimeError => e raise unless e.message =~ /new record/ state = nil end
Prevention
- Never read association-backed state on unsaved records
- create! enrollments in specs rather than building
- Ensure callbacks that touch enrollment_state run post-persist
When it happens
Trigger: Calling enrollment.enrollment_state on a build/new Enrollment that has not been saved — e.g. computing state before create, or create_enrollment_state invoked on an unsaved enrollment in a callback-order bug.
Common situations: Specs calling enrollment_state on Enrollment.new; after_build-style code touching enrollment_state before save; code paths that construct transient enrollments for previews or invitations.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- can't accept
- assessor and assessee required
- association required
- can only forward one conversation at a time
- Can't update submission scores unless it's completed
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/5be538f02d64f036.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/enrollment.rb:842
end
state :deleted
state :rejected do
event :unreject, transitions_to: :invited
end
state :completed
# Inactive is a "hard" state, i.e. tuition not paid
state :inactive
end
def enrollment_dates
Canvas::Builders::EnrollmentDateBuilder.preload([self]) unless @enrollment_dates
@enrollment_dates
end
def enrollment_state
raise "cannot call enrollment_state on a new record" if new_record?
result = super
unless result
association(:enrollment_state).reload
result = super
end
# ensure we have an enrollment state object present with a reverse association
result ||= create_enrollment_state
result.enrollment = self
result
end
def create_enrollment_state
self.enrollment_state =
shard.activate do
GuardRail.activate(:primary) do
EnrollmentState.unique_constraint_retry do
EnrollmentState.where(enrollment_id: self).first_or_createView on GitHub (pinned to 1c9f0bb801)