instructure/canvas-lms · error · RuntimeError
Artifact required for assessing
Error message
Artifact required for assessing
What it means
RubricAssociation#assess requires an :artifact — the object being assessed (e.g. a Submission or QuizSubmission). This guard fires when opts[:artifact] is nil/absent, so Canvas has nothing to attach the rubric assessment to. It is a fail-fast contract check before the artifact is normalized or assessment rows are created.
Solutions
- Pass the artifact explicitly: ra.assess(user: student, assessor: assessor, artifact: submission, assessment: {assessment_type: 'grading'})
- Resolve the Submission first and bail out early if nil: submission = assignment.submissions.find_by(user: student) or handle absence before assessing
- For quizzes, you may pass the Quizzes::QuizSubmission itself — assess converts it internally — but it must not be nil
Example fix
// before submission = assignment.submissions.find_by(user_id: student.id) # may be nil rubric_association.assess(user: student, assessor: assessor, artifact: submission, ...) // after submission = assignment.submissions.find_by!(user_id: student.id) raise 'submission not found' unless submission rubric_association.assess(user: student, assessor: assessor, artifact: submission, ...)
Defensive patterns
Strategy: validation
Validate before calling
raise 'artifact required' if opts[:artifact].nil? rubric_association.assess(user:, assessor:, artifact: submission, assessment:)
Type guard
valid = opts[:artifact].is_a?(Submission) || opts[:artifact].is_a?(Quizzes::QuizSubmission)
Try / catch
begin rubric_association.assess(opts) rescue RuntimeError => e handle_missing_artifact if e.message == 'Artifact required for assessing' end
Prevention
- Resolve the Submission with find_by! so nil lookups fail early
- Pass the QuizSubmission directly for quizzes; assess normalizes it
- Unit-test assess calls with all four required params
When it happens
Trigger: Calling rubric_association.assess(user:, assessor:, assessment: {...}) without opts[:artifact]; artifact lookup returning nil before the call (e.g. Submission.find_by(...) found nothing); passing an artifact key with the wrong name so opts[:artifact] stays nil.
Common situations: Scripts automating rubric grading where the submission lookup failed silently; LTI/tool integrations constructing the assess params themselves; quiz-submission flows where the artifact was expected to be created later but assess is called first.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Assessment type required for assessing
- Assessor required for assessing
- assessor and assessee required
- association required
- Cannot find # for ID: #
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/b7301553f2a0deda.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/rubric_association.rb:310
def assessment_points(criterion, data)
if criterion.learning_outcome_id && !context.feature_enabled?(:outcome_extra_credit)
[criterion.points, data[:points].to_f].min
else
data[:points].to_f
end
end
protected :assessment_points
def assess(opts = {})
# TODO: what if this is for a group assignment? Seems like it should
# give all students for the group assignment the same rubric assessment
# results.
association = self
params = opts[:assessment]
raise "User required for assessing" unless opts[:user]
raise "Assessor required for assessing" unless opts[:assessor]
raise "Artifact required for assessing" unless opts[:artifact]
raise "Assessment type required for assessing" unless params[:assessment_type]
if opts[:artifact].is_a?(Quizzes::QuizSubmission)
opts[:artifact] = association_object.find_or_create_submission(opts[:artifact].user)
end
if association_object.is_a?(Assignment) && !association_object.grade_group_students_individually
group, students_to_assess = association_object.group_students(opts[:artifact].student)
if group
provisional_grader = opts[:artifact].is_a?(ModeratedGrading::ProvisionalGrade) && opts[:assessor]
artifacts_to_assess = students_to_assess.map do |student|
association_object.find_asset_for_assessment(self, student, provisional_grader:).first
end
else
artifacts_to_assess = [opts[:artifact]]
end
else
artifacts_to_assess = [opts[:artifact]]View on GitHub (pinned to 1c9f0bb801)