{"record":{"id":"f98d4170fdf1db7a","repo":"instructure/canvas-lms","slug":"checkpoint-checkpoint-label-not-found","errorCode":null,"errorMessage":"Checkpoint '#{@checkpoint_label}' not found","messagePattern":"Checkpoint '#(.+?)' not found","errorType":"exception","errorClass":"Checkpoints::CheckpointNotFoundError","httpStatus":null,"severity":"error","filePath":"app/services/checkpoints/discussion_checkpoint_updater_service.rb","lineNumber":40,"sourceCode":"    validate_flag_enabled\n    validate_dates\n\n    checkpoint = find_checkpoint\n    compute_due_dates_and_create_submissions(checkpoint)\n    checkpoint.saved_by = @saved_by\n    checkpoint.updating_user = @updating_user\n    checkpoint.save!\n    checkpoint.saved_by = nil\n    checkpoint\n  end\n\n  private\n\n  def find_checkpoint\n    @discussion_topic.update!(reply_to_entry_required_count: @replies_required) if update_required_replies?\n    checkpoint = @assignment.sub_assignments.find_by(sub_assignment_tag: @checkpoint_label)\n\n    raise Checkpoints::CheckpointNotFoundError, \"Checkpoint '#{@checkpoint_label}' not found\" unless checkpoint\n\n    # Only assign attributes that have actually changed to avoid triggering\n    # Master Course validation on unchanged restricted columns\n    changed_attributes = checkpoint_attributes_for_update(checkpoint)\n    checkpoint.assign_attributes(changed_attributes) if changed_attributes.any?\n\n    update_overrides = override_dates.select { |override| override[:id].present? }\n    new_overrides = override_dates.select { |override| override[:id].nil? }\n    existing_overrides = checkpoint.assignment_overrides\n\n    override_ids_to_delete = existing_overrides.pluck(:id) - update_overrides.pluck(:id)\n\n    # 1. Remove overrides that are no longer present\n    if override_ids_to_delete.any?\n      parent_override_ids = checkpoint.assignment_overrides.where(id: override_ids_to_delete).pluck(:parent_override_id)\n      checkpoint.assignment_overrides.where(id: override_ids_to_delete).destroy_all\n\n      AssignmentOverride.where(id: parent_override_ids).destroy_all","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/services/checkpoints/discussion_checkpoint_updater_service.rb#L22-L58","documentation":"DiscussionCheckpointUpdaterService#find_checkpoint looks up a sub-assignment by sub_assignment_tag matching @checkpoint_label (e.g. 'reply_to_topic' or 'reply_to_entry') and raises CheckpointNotFoundError if none exists. The updater can only modify checkpoints that actually exist on the parent assignment.","triggerScenarios":"Calling the updater with checkpoint_label that doesn't match any sub_assignment_tag on the assignment — misspelled tag, tag on a different assignment, or the assignment has no sub_assignments at all.","commonSituations":"API clients using wrong tag strings ('replies' vs 'reply_to_entry'); applying an update payload built for one discussion to another; the checkpoints having been deleted (checkpoints flag disabled) while updates keep arriving; case/whitespace differences in tags.","solutions":["Verify @checkpoint_label exactly matches an existing sub_assignment_tag: assignment.sub_assignments.pluck(:sub_assignment_tag).","Create the checkpoint first (creator service) before updating it.","Trim/canonicalize the tag at the API boundary to avoid whitespace/case mismatches."],"exampleFix":"// before\nupdater.call(assignment: a, checkpoint_label: 'replies', ...)\n// after\nupdater.call(assignment: a, checkpoint_label: 'reply_to_entry', ...)","handlingStrategy":"try-catch","validationCode":"tags = assignment.sub_assignments.pluck(:sub_assignment_tag)\nraise ArgumentError, \"unknown checkpoint #{label}\" unless tags.include?(label)","typeGuard":"def checkpoint_exists?(assignment, label)\n  assignment.sub_assignments.exists?(sub_assignment_tag: label)\nend","tryCatchPattern":"begin\n  Checkpoints::DiscussionCheckpointUpdaterService.call(assignment:, checkpoint_label: label, ...)\nrescue Checkpoints::CheckpointNotFoundError => e\n  render json: { error: e.message }, status: :not_found\nend","preventionTips":["Fetch valid checkpoint labels from the assignment before building update payloads","Don't reuse update payloads across different discussions","Ensure checkpoints exist (creator ran) before issuing updates"],"tags":["ruby","canvas","resource-not-found","checkpoints"],"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"}