instructure/canvas-lms · error · ArgumentError
Cannot call with more than one user
Error message
Cannot call with more than one user
What it means
Enrollment.recompute_final_score_in_singleton schedules a singleton delayed job to recompute a final score for exactly one user in one course. The singleton key embeds user_id, so multiple users would collide; it raises ArgumentError if Array(user_id).size > 1.
Solutions
- Call the method once per user_id in a loop.
- Use Enrollment.recompute_final_score (plural) for batches.
- Assert Array(user_id).size == 1 at the call site before invoking.
Example fix
// before
Enrollment.recompute_final_score_in_singleton(user_ids, course_id)
// after
user_ids.each { |uid| Enrollment.recompute_final_score_in_singleton(uid, course_id) } Defensive patterns
Strategy: validation
Validate before calling
raise "expected a single user id" unless Array(user_id).size == 1
Try / catch
begin
Enrollment.recompute_final_score_in_singleton(user_id, course_id)
rescue ArgumentError
user_ids.each { |uid| Enrollment.recompute_final_score_in_singleton(uid, course_id) }
end Prevention
- Never pass arrays to *_in_singleton methods
- Loop over ids at the call site
- Keep singleton call sites single-purpose
When it happens
Trigger: Calling Enrollment.recompute_final_score_in_singleton([1,2,3], course_id) or passing a collection/relation of users instead of a single id.
Common situations: Batch recomputation after grading changes: developer passes an array of student ids to the singleton variant instead of looping or using the plural method.
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
- Searching for announcements in sections must span exactly…
- A course did not pass validation
- A # user did not pass validation (user: # , # : # , error…
- A # did not pass validation (# : # , error: # )
- A # did not pass validation (# : # , error: # )
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/039bdb5451b860a1.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/enrollment.rb:1136
# * An assignment is deleted/undeleted
#
# * An enrollment is accepted (to address the scenario where a student
# is transferred from one section to another, and final grades need
# to be transferred)
#
# If some new feature comes up that affects calculation of a user's score,
# please add appropriate calls to this so that the cached values don't get
# stale! And once you've added the call, add the condition to the comment
# here for future enlightenment.
def self.recompute_final_score(*, **)
GradeCalculator.recompute_final_score(*, **)
end
# This method is intended to not duplicate work for a single user.
def self.recompute_final_score_in_singleton(user_id, course_id, **opts)
# Guard against getting more than one user_id
raise ArgumentError, "Cannot call with more than one user" if Array(user_id).size > 1
delay_if_production(singleton: "Enrollment.recompute_final_score:#{user_id}:#{course_id}:#{opts[:grading_period_id]}",
max_attempts: 10)
.recompute_final_score(user_id, course_id, **opts)
end
def self.recompute_due_dates_and_scores(user_id)
Course.where(id: StudentEnrollment.where(user_id:).distinct.select(:course_id)).each do |course|
SubmissionLifecycleManager.recompute_users_for_course([user_id], course, nil, update_grades: true)
end
end
def self.recompute_final_scores(user_id)
StudentEnrollment.where(user_id:).distinct.pluck(:course_id).each do |course_id|
recompute_final_score_in_singleton(user_id, course_id)
end
end
View on GitHub (pinned to 1c9f0bb801)