{"record":{"id":"0234885007ed4a69","repo":"instructure/canvas-lms","slug":"peer-review-sub-assignment-does-not-exist","errorCode":null,"errorMessage":"Peer review sub assignment does not exist","messagePattern":"Peer review sub assignment does not exist","errorType":"validation","errorClass":"PeerReview::SubAssignmentNotExistError","httpStatus":null,"severity":"error","filePath":"app/services/peer_review/validations.rb","lineNumber":55,"sourceCode":"  end\n\n  def validate_grading_type(grading_type)\n    raise PeerReview::InvalidGradingTypeError, I18n.t(\"Peer review sub assignments cannot have a not_graded grading type\") if grading_type == \"not_graded\"\n  end\n\n  def validate_assignment_submission_types(assignment)\n    if assignment.external_tool?\n      raise PeerReview::InvalidAssignmentSubmissionTypesError, I18n.t(\"Peer reviews cannot be used with External Tool assignments\")\n    end\n\n    if assignment.submission_types == \"discussion_topic\"\n      raise PeerReview::InvalidAssignmentSubmissionTypesError, I18n.t(\"Peer reviews cannot be used with Discussion Topic assignments\")\n    end\n  end\n\n  def validate_peer_review_sub_assignment_exists(assignment)\n    if assignment.peer_review_sub_assignment.blank?\n      raise PeerReview::SubAssignmentNotExistError, I18n.t(\"Peer review sub assignment does not exist\")\n    end\n  end\n\n  def validate_peer_review_sub_assignment_not_exist(assignment)\n    if assignment.peer_review_sub_assignment.present?\n      raise PeerReview::SubAssignmentExistsError, I18n.t(\"Peer review sub assignment exists\")\n    end\n  end\n\n  # Validates that peer review dates follow the restriction below\n  # peer review unlock_at < peer review due_at <= peer review lock_at\n  def validate_peer_review_dates(peer_review_dates)\n    parsed_dates = {}\n\n    %w[due_at unlock_at lock_at].each do |date_field|\n      date_value = peer_review_dates.fetch(date_field.to_sym, nil)\n      next unless date_value.present?\n","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/services/peer_review/validations.rb#L37-L73","documentation":"PeerReview::Validations#validate_peer_review_sub_assignment_exists raises PeerReview::SubAssignmentNotExistError when `assignment.peer_review_sub_assignment` is blank, i.e. the operation expects an existing peer review sub assignment (typically update/delete flows) but none has been created yet.","triggerScenarios":"Updating or deleting the peer review sub assignment of an assignment that never had one created; calling sync/update services before SubAssignmentCreator ran; the sub assignment having been deleted earlier.","commonSituations":"Race between sub assignment deletion and an update job; feature flag turned on later so legacy assignments have no sub assignment; re-running migrations/sync scripts on fresh assignments.","solutions":["Create the sub assignment first via the creation service, then update it.","Guard update/delete calls with `assignment.peer_review_sub_assignment.present?` and no-op (or create) when absent.","Reconcile data: run the backfill that creates sub assignments for assignments with peer_reviews enabled."],"exampleFix":"// before\nPeerReview::SubAssignmentUpdater.new(assignment: assignment).call # no sub assignment yet\n// after\nif assignment.peer_review_sub_assignment.blank?\n  PeerReview::SubAssignmentCreator.new(assignment: assignment).call\nend\nPeerReview::SubAssignmentUpdater.new(assignment: assignment).call","handlingStrategy":"validation","validationCode":"return render json: { error: \"no sub assignment\" }, status: :not_found if assignment.peer_review_sub_assignment.blank?","typeGuard":"def sub_assignment_exists?(assignment) = assignment.peer_review_sub_assignment.present?","tryCatchPattern":"begin\n  updater.call\nrescue PeerReview::SubAssignmentNotExistError\n  create_sub_assignment(assignment)\nend","preventionTips":["Create the sub assignment before scheduling update/delete jobs","Use present?/blank? guards on peer_review_sub_assignment","Backfill sub assignments for legacy peer-review-enabled assignments"],"tags":["peer-review","rails","record-missing","validation"],"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"}