{"record":{"id":"122a8fc126b9e8f4","repo":"instructure/canvas-lms","slug":"can-t-update-submission-scores-unless-it-s-completed","errorCode":null,"errorMessage":"Can't update submission scores unless it's completed","messagePattern":"Can't update submission scores unless it's completed","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"app/models/quizzes/quiz_submission.rb","lineNumber":756,"sourceCode":"        if finished_at\n          quiz.context_module_action(user, :submitted, kept_score) # pass in the score so we don't accidentally unset a min_score requirement\n        end\n      end\n    end\n  end\n\n  def update_scores(params)\n    original_score = score\n    original_workflow_state = workflow_state\n    params = (params || {}).with_indifferent_access\n    self.manually_scored = false\n    self.grader_id = params[:grader_id]\n    submission&.mark_unread(user)\n    versions = self.versions\n    version = versions.current\n    version = versions.get(params[:submission_version_number]) if params[:submission_version_number]\n    # NOTE: that self may not match versions.current, because we only save a new version on actual submit\n    raise \"Can't update submission scores unless it's completed\" if !completed? && !params[:submission_version_number]\n\n    data = version.model.submission_data || []\n    res = []\n    tally = 0\n    completed_before_changes = completed?\n    self.workflow_state = \"complete\"\n    self.fudge_points = params[:fudge_points].to_f if params[:fudge_points] && params[:fudge_points] != \"\"\n    tally += fudge_points if fudge_points\n    data.each do |answer|\n      unless answer.respond_to?(:with_indifferent_access)\n        logger.error \"submission = #{to_json}\"\n        logger.error \"answer = #{answer.inspect}\"\n        raise \"Quizzes::QuizSubmission.update_scores called on a quiz that appears to be in progress\"\n      end\n      answer = answer.with_indifferent_access\n      score = params[:\"question_score_#{answer[\"question_id\"]}\"]\n      answer[\"more_comments\"] = params[:\"question_comment_#{answer[\"question_id\"]}\"] if params[:\"question_comment_#{answer[\"question_id\"]}\"]\n      if score.present?","sourceCodeStart":738,"sourceCodeEnd":774,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/quizzes/quiz_submission.rb#L738-L774","documentation":"QuizSubmission#update_scores applies teacher-entered scores to the current submission version, but only meaningful on a completed submission. Canvas raises this RuntimeError unless completed? or an explicit submission_version_number param targets a historical version. It prevents regrading quizzes still in progress.","triggerScenarios":"Calling update_scores (e.g. from controller regrade actions) for a submission whose workflow_state is not complete, without passing submission_version_number.","commonSituations":"Teacher grading UI open across a student re-attempt; scripts regrading submissions mid-attempt; a student retaking a quiz while scores are being posted; moderator/extension flows resetting attempts.","solutions":["Wait for or force completion of the submission before updating scores","Pass params[:submission_version_number] pointing to a completed historical version to score that version instead","Check quiz_submission.completed? before calling update_scores and skip or queue the update","Ensure the user cannot be actively taking the quiz when grading (lock the attempt)"],"exampleFix":"// before\nsubmission.update_scores(current_user, params)\n// after\nif submission.completed? || params[:submission_version_number]\n  submission.update_scores(current_user, params)\nelse\n  raise QuizSubmissionNotCompleted\nend","handlingStrategy":"validation","validationCode":"raise ScoresUpdateNotAllowed unless submission.completed? || params[:submission_version_number].present?","typeGuard":null,"tryCatchPattern":"begin\n  submission.update_scores(user, params)\nrescue RuntimeError => e\n  raise unless e.message.include?(\"unless it's completed\")\n  queue_regrade_when_completed(submission, params)\nend","preventionTips":["Check completed? before score updates","Pass submission_version_number for historical versions","Lock in-progress attempts before manual grading"],"tags":["ruby","rails","quiz-submission","grading","invalid-state"],"backgroundTag":"invalid-state-transition","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"}