instructure/canvas-lms · error · Checkpoints::CheckpointNotFoundError

Checkpoint '# ' not found

Error message

Checkpoint '#{@checkpoint_label}' not found

What it means

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.

Solutions

  1. Verify @checkpoint_label exactly matches an existing sub_assignment_tag: assignment.sub_assignments.pluck(:sub_assignment_tag).
  2. Create the checkpoint first (creator service) before updating it.
  3. Trim/canonicalize the tag at the API boundary to avoid whitespace/case mismatches.

Example fix

// before
updater.call(assignment: a, checkpoint_label: 'replies', ...)
// after
updater.call(assignment: a, checkpoint_label: 'reply_to_entry', ...)
Defensive patterns

Strategy: try-catch

Validate before calling

tags = assignment.sub_assignments.pluck(:sub_assignment_tag)
raise ArgumentError, "unknown checkpoint #{label}" unless tags.include?(label)

Type guard

def checkpoint_exists?(assignment, label)
  assignment.sub_assignments.exists?(sub_assignment_tag: label)
end

Try / catch

begin
  Checkpoints::DiscussionCheckpointUpdaterService.call(assignment:, checkpoint_label: label, ...)
rescue Checkpoints::CheckpointNotFoundError => e
  render json: { error: e.message }, status: :not_found
end

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/f98d4170fdf1db7a. Report an issue: GitHub.

Appendix: source

Thrown at app/services/checkpoints/discussion_checkpoint_updater_service.rb:40

    validate_flag_enabled
    validate_dates

    checkpoint = find_checkpoint
    compute_due_dates_and_create_submissions(checkpoint)
    checkpoint.saved_by = @saved_by
    checkpoint.updating_user = @updating_user
    checkpoint.save!
    checkpoint.saved_by = nil
    checkpoint
  end

  private

  def find_checkpoint
    @discussion_topic.update!(reply_to_entry_required_count: @replies_required) if update_required_replies?
    checkpoint = @assignment.sub_assignments.find_by(sub_assignment_tag: @checkpoint_label)

    raise Checkpoints::CheckpointNotFoundError, "Checkpoint '#{@checkpoint_label}' not found" unless checkpoint

    # Only assign attributes that have actually changed to avoid triggering
    # Master Course validation on unchanged restricted columns
    changed_attributes = checkpoint_attributes_for_update(checkpoint)
    checkpoint.assign_attributes(changed_attributes) if changed_attributes.any?

    update_overrides = override_dates.select { |override| override[:id].present? }
    new_overrides = override_dates.select { |override| override[:id].nil? }
    existing_overrides = checkpoint.assignment_overrides

    override_ids_to_delete = existing_overrides.pluck(:id) - update_overrides.pluck(:id)

    # 1. Remove overrides that are no longer present
    if override_ids_to_delete.any?
      parent_override_ids = checkpoint.assignment_overrides.where(id: override_ids_to_delete).pluck(:parent_override_id)
      checkpoint.assignment_overrides.where(id: override_ids_to_delete).destroy_all

      AssignmentOverride.where(id: parent_override_ids).destroy_all

View on GitHub (pinned to 1c9f0bb801)