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

set_id is required, but was not provided

Error message

set_id is required, but was not provided

What it means

Checkpoints::SetIdRequiredError raised by Checkpoints::GroupOverrideCommon#get_group_from_override when the override hash passed in has no :set_id key. The method uses Hash#fetch with a raise-on-missing block, so any group override payload lacking set_id aborts before the group is looked up. It exists to fail fast with a clear message instead of a confusing nil find.

Solutions

  1. Add set_id (the group id) to the override hash before calling the service
  2. Ensure the client always submits set_id for group overrides, not only on change
  3. If the override already exists, read set_id from the persisted AssignmentOverride (override.set_id) as the updater service does
  4. Rescue Checkpoints::SetIdRequiredError at the controller boundary and return 400 with the message

Example fix

// before
service = Checkpoints::GroupOverrideCreatorService.new(checkpoint, { due_at: t })
// after
service = Checkpoints::GroupOverrideCreatorService.new(checkpoint, { set_id: group.id, due_at: t })
Defensive patterns

Strategy: validation

Validate before calling

raise ArgumentError, 'set_id is required' unless override.is_a?(Hash) && override[:set_id].present?
# then call the service
Checkpoints::GroupOverrideCreatorService.new(checkpoint, override).call

Type guard

def valid_group_override?(override)
  override.is_a?(Hash) && override[:set_id].present?
end

Try / catch

begin
  Checkpoints::GroupOverrideCreatorService.new(checkpoint, override).call
rescue Checkpoints::SetIdRequiredError => e
  render json: { errors: ['set_id is required for group overrides'] }, status: :bad_request
end

Prevention

When it happens

Trigger: Calling get_group_from_override with an override hash that omits the :set_id key, e.g. creating/updating a group-set checkpoint override from a form that did not submit set_id or called the service with {assignment_override: {...}} minus set_id.

Common situations: API clients posting checkpoint overrides without set_id; frontend diffing code that only sends changed attributes so set_id is dropped on unchanged overrides; refactors that renamed group_id to set_id but callers still send the old key.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at app/services/checkpoints/group_override_common.rb:37

module Checkpoints::GroupOverrideCommon
  # Differentiaiton tags are allowed to be used as group overrides
  # This method determines if the override is associated with a
  # differentiation tag in the checkpoint's course
  def differentiation_tag_override?(override, checkpoint)
    return false unless differentiation_tags_enabled_for_context?(checkpoint)

    group = get_differentiation_tag_from_override(override, checkpoint)

    if group.nil?
      return false
    end

    group.non_collaborative
  end

  def get_group_from_override(override, checkpoint)
    group_id = override.fetch(:set_id) { raise Checkpoints::SetIdRequiredError, "set_id is required, but was not provided" }
    checkpoint.course.active_groups.where(group_category_id: checkpoint.effective_group_category_id).find(group_id)
  end

  def get_differentiation_tag_from_override(override, checkpoint)
    tag_id = override.fetch(:set_id) { raise Checkpoints::SetIdRequiredError, "set_id is required, but was not provided" }
    checkpoint.course.differentiation_tags.where(id: tag_id).first
  end

  private

  def differentiation_tags_enabled_for_context?(checkpoint)
    account = checkpoint.course.account
    account.allow_assign_to_differentiation_tags?
  end
end

View on GitHub (pinned to 1c9f0bb801)