{"record":{"id":"c761143bd2326bd4","repo":"instructure/canvas-lms","slug":"assessor-required-for-assessing","errorCode":null,"errorMessage":"Assessor required for assessing","messagePattern":"Assessor required for assessing","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"app/models/rubric_association.rb","lineNumber":309,"sourceCode":"  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\n    else","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/rubric_association.rb#L291-L327","documentation":"RubricAssociation#assess requires the caller to supply a hash of options including :user, :assessor, :artifact, and the assessment params. This guard fires when opts[:assessor] is nil/absent, meaning Canvas cannot record who performed the rubric assessment. It is a fail-fast contract check before any assessment rows are created.","triggerScenarios":"Calling rubric_association.assess(user:, artifact:, assessment: {...}) without opts[:assessor]; callers building the assess params hash programmatically (e.g. from an API request or LTI tool) and omitting the assessor id; assessor object resolved to nil because the supplied user id does not map to a real user with grading rights.","commonSituations":"Custom integrations or scripts that call assess directly and copy the wrong param key (e.g. :assessor_id instead of :assessor); third-party rubric tools passing incomplete params; refactors that removed the assessor lookup but left the assess call in place.","solutions":["Pass opts[:assessor] with the User (or user object) performing the assessment: ra.assess(user: student, assessor: teacher, artifact: submission, assessment: {assessment_type: 'grading'})","Verify the assessor is resolved before calling assess (e.g. assessor = User.find(teacher_id); raise early with a friendlier message if nil)","If integrating via the Submissions/Assessments API, confirm the endpoint supplies the assessor (the current user) rather than only the student"],"exampleFix":"// before\nrubric_association.assess(\n  user: student,\n  artifact: submission,\n  assessment: { assessment_type: 'grading', ... }\n)\n// after\nrubric_association.assess(\n  user: student,\n  assessor: current_user,\n  artifact: submission,\n  assessment: { assessment_type: 'grading', ... }\n)","handlingStrategy":"validation","validationCode":"raise 'assessor required' unless opts[:assessor]\nrubric_association.assess(user:, assessor:, artifact:, assessment:)","typeGuard":"valid = opts[:assessor].is_a?(User)\n","tryCatchPattern":"begin\n  rubric_association.assess(opts)\nrescue RuntimeError => e\n  handle_missing_assessor if e.message == 'Assessor required for assessing'\nend","preventionTips":["Always pass the performing teacher/user as :assessor","Build assess params via a shared helper that asserts all required keys","Add request specs covering rubric assessment creation"],"tags":["rubric","missing-argument","ruby"],"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"}