{"record":{"id":"762bf6132d81bb00","repo":"instructure/canvas-lms","slug":"user-required-for-assessing","errorCode":null,"errorMessage":"User required for assessing","messagePattern":"User required for assessing","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"app/models/rubric_association.rb","lineNumber":308,"sourceCode":"    association_object.is_a?(Assignment) && purpose == \"grading\" && assessment_type == \"grading\"\n  end\n\n  def assessment_points(criterion, data)\n    if criterion.learning_outcome_id && !context.feature_enabled?(:outcome_extra_credit)\n      [criterion.points, data[:points].to_f].min\n    else\n      data[:points].to_f\n    end\n  end\n  protected :assessment_points\n\n  def assess(opts = {})\n    # TODO: what if this is for a group assignment?  Seems like it should\n    # give all students for the group assignment the same rubric assessment\n    # results.\n    association = self\n    params = opts[:assessment]\n    raise \"User required for assessing\" unless opts[:user]\n    raise \"Assessor required for assessing\" unless opts[:assessor]\n    raise \"Artifact required for assessing\" unless opts[:artifact]\n    raise \"Assessment type required for assessing\" unless params[:assessment_type]\n\n    if opts[:artifact].is_a?(Quizzes::QuizSubmission)\n      opts[:artifact] = association_object.find_or_create_submission(opts[:artifact].user)\n    end\n\n    if association_object.is_a?(Assignment) && !association_object.grade_group_students_individually\n      group, students_to_assess = association_object.group_students(opts[:artifact].student)\n      if group\n        provisional_grader = opts[:artifact].is_a?(ModeratedGrading::ProvisionalGrade) && opts[:assessor]\n        artifacts_to_assess = students_to_assess.map do |student|\n          association_object.find_asset_for_assessment(self, student, provisional_grader:).first\n        end\n      else\n        artifacts_to_assess = [opts[:artifact]]\n      end","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/rubric_association.rb#L290-L326","documentation":"RubricAssociation#assess creates a rubric assessment and requires opts to include :user (the student being assessed), :assessor, :artifact, and an assessment_type inside opts[:assessment]. Canvas raises this RuntimeError when opts[:user] is missing, since the artifact/assessment must be tied to a person.","triggerScenarios":"Calling association.assess(assessment: {...}, assessor: x, artifact: y) without opts[:user]; or user derived from an artifact that is nil.","commonSituations":"Custom rubric-assessment controllers or scripts that forget :user; peer-review automation where the submission's user cannot be resolved; old code paths using positional args against the new opts API.","solutions":["Pass opts[:user] (the assessed student) along with assessor and artifact in the assess call","Derive user from the artifact, e.g. user: submission.user, before calling assess","Add the remaining required opts too: :assessor, :artifact, and params[:assessment][:assessment_type] to avoid the following raises"],"exampleFix":"// before\nassoc.assess(assessment: { assessment_type: \"grading\" }, assessor: teacher, artifact: submission)\n// after\nassoc.assess(user: submission.user, assessor: teacher, artifact: submission,\n             assessment: { assessment_type: \"grading\" })","handlingStrategy":"validation","validationCode":"raise ArgumentError, \"user, assessor, artifact and assessment_type required\" unless opts[:user] && opts[:assessor] && opts[:artifact] && opts.dig(:assessment, :assessment_type)","typeGuard":"def assessable_opts?(opts) = opts[:user].is_a?(User) && opts[:assessor].is_a?(User) && !opts[:artifact].nil? && opts.dig(:assessment, :assessment_type).present?","tryCatchPattern":"begin\n  assoc.assess(opts)\nrescue RuntimeError => e\n  raise unless e.message.include?(\"required for assessing\")\n  Rails.logger.error(\"invalid assess opts: #{opts.keys.inspect}\")\nend","preventionTips":["Build the full opts hash (user, assessor, artifact, assessment_type) in one place","Derive user from artifact.user when unsure","Unit-test assess callers with all required keys present"],"tags":["ruby","rails","rubrics","missing-argument"],"backgroundTag":"missing-required-argument","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}