{"record":{"id":"8dc7df6d41556baa","repo":"instructure/canvas-lms","slug":"could-not-find-valid-answer","errorCode":null,"errorMessage":"Could not find valid answer","messagePattern":"Could not find valid answer","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"app/models/quizzes/quiz_outcome_result_builder.rb","lineNumber":58,"sourceCode":"\n    def create_outcome_question_result(question, alignment)\n      # find or create the user's unique LearningOutcomeResult for this alignment\n      # of the quiz question.\n      quiz_result = alignment.learning_outcome_results\n                             .for_association(@qs.quiz)\n                             .for_associated_asset(@qs.quiz)\n                             .where(user_id: @qs.user.id)\n                             .first_or_initialize\n\n      quiz_result.workflow_state = :active\n      quiz_result.user_uuid = @qs.user.uuid\n\n      # get data from quiz submission's question result to ensure result should be generated\n      cached_question = @qs.quiz_data.detect { |q| q[:assessment_question_id] == question.id }\n      raise \"Could not find valid question\" unless cached_question\n\n      cached_answer = @qs.submission_data.detect { |q| q[:question_id] == cached_question[:id] }\n      raise \"Could not find valid answer\" unless cached_answer\n\n      # Create a question scoped outcome result linked to the quiz_result.\n      question_result = quiz_result.learning_outcome_question_results.for_associated_asset(question).first_or_initialize\n\n      # do not create a result if no points are possible.\n      if cached_question[\"points_possible\"] == 0\n        # destroy any existing results that might be persisted if points possible were not always 0\n        question_result.destroy if question_result.persisted?\n        return\n      end\n\n      # update the result with stuff from the quiz submission's question result\n      question_result.learning_outcome = quiz_result.learning_outcome\n\n      # mastery\n      question_result.score = cached_answer[:points]\n      question_result.possible = cached_question[\"points_possible\"]\n      question_result.calculate_percent!","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/quizzes/quiz_outcome_result_builder.rb#L40-L76","documentation":"Quizzes::QuizOutcomeResultBuilder#create_outcome_question_result raises when the student's submission_data contains no answer for the cached question (matched by question_id). The submission snapshot has the question but no recorded answer record, so an outcome result for that question cannot be built.","triggerScenarios":"@qs.submission_data lacks an entry whose :question_id equals cached_question[:id] — e.g. the question was added to quiz_data after submission, answer data was pruned, or an unanswered/skipped question produced no submission_data entry.","commonSituations":"Student never answered the question and no placeholder answer record exists; quiz_data and submission_data versions are out of sync; external/essay questions migrated leaving inconsistent snapshots; data cleanup jobs removed submission_data entries.","solutions":["Inspect the quiz submission's submission_data to see which question_ids are present","Confirm the student actually answered that question; skip outcome result generation for unanswered questions","Guard with a conditional skip rather than raise when cached_answer is nil","Re-generate submission_data (regrade/rebuild snapshot) if it is corrupted relative to quiz_data"],"exampleFix":"// before\nraise \"Could not find valid answer\" unless cached_answer\n// after\ncached_answer = @qs.submission_data.detect { |q| q[:question_id] == cached_question[:id] }\nnext unless cached_answer\n","handlingStrategy":"validation","validationCode":"next unless @qs.quiz_data&.any? { |q| q[:assessment_question_id] == question.id } &&\n  @qs.submission_data.to_a.any? { |a| a[:question_id].to_s == cached_question[:id].to_s }","typeGuard":"has_answer = ->(qs, qid) { qs.submission_data.to_a.any? { |a| a[:question_id].to_s == qid.to_s } }","tryCatchPattern":"begin\n  builder.build_outcome_results(alignment, questions)\nrescue RuntimeError => e\n  Rails.logger.warn(\"skipping question without answer: #{e.message}\")\nend","preventionTips":["Treat unanswered questions as zero-score skips rather than hard failures","Normalize question_id comparisons (to_s) between quiz_data and submission_data","Regenerate/rebuild submission snapshots if they drift from quiz_data","Exclude never-answered questions from outcome result generation upfront"],"tags":["quizzes","outcomes","submission-data"],"backgroundTag":"record-not-found","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"}