instructure/canvas-lms · error · GraphQL::ExecutionError

Invalid section ids

Error message

Invalid section ids

What it means

HideAssignmentGradesForSections mutation rejects the request when the set of CourseSection records resolved from section_ids does not exactly match the section_ids the caller sent. Either no sections matched (empty) or some ids did not resolve to sections of the assignment's course. It is a caller-input validation guard before the hide-submissions job is queued.

Solutions

  1. Query the course's course_sections (active only) and send only ids that belong to assignment.context_id
  2. Re-fetch section ids via GraphQL (course.sections connection) instead of caching them
  3. Ensure ids are the accepted format (relay global ids via the mutation's prepare helper or plain legacy numeric ids)
  4. Check for duplicate ids in the payload; duplicates plus any unresolvable id cause a count mismatch

Example fix

// before
hideAssignmentGradesForSections(input: { assignmentId: "1", sectionIds: ["12", "99"] }) // 99 not in course
// after
const ids = course.sections.connection.filter(s => s.courseId === assignment.courseId).map(s => s.id);
hideAssignmentGradesForSections(input: { assignmentId: "1", sectionIds: ids });
Defensive patterns

Strategy: validation

Validate before calling

const ids = input.sectionIds;
const sections = (await course.sectionsConnection).filter(s => ids.includes(s.id));
if (sections.length !== ids.length || ids.length === 0) throw new Error("Invalid section ids");

Try / catch

try {
  await hideAssignmentGradesForSections(input);
} catch (e) {
  if (e.message.includes("Invalid section ids")) {
    // refresh section ids from the course and retry once
  }
}

Prevention

When it happens

Trigger: Calling mutation hideAssignmentGradesForSections with section_ids containing: ids that belong to a different course, already-deleted sections, malformed/garbage ids, duplicates combined with an unresolvable id (count mismatch), or a mix of relay and legacy ids that do not all resolve.

Common situations: Cross-course copy-paste of section ids; using sections from a course after section merges/deletions; passing section ids from a staging database into a production request; hardcoding section ids that changed between environments; sending both relay global ids and numeric legacy ids mixed.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at app/graphql/mutations/hide_assignment_grades_for_sections.rb:48

  def resolve(input:)
    begin
      assignment = AbstractAssignment.find_assignment_or_peer_review(input[:assignment_id])
      course = assignment.context
      sections = course.course_sections.where(id: input[:section_ids])
    rescue ActiveRecord::RecordNotFound
      raise GraphQL::ExecutionError, "not found"
    end

    verify_authorized_action!(assignment, :grade)

    unless assignment.grades_published?
      raise GraphQL::ExecutionError, "Assignments under moderation cannot be hidden by section before grades are published"
    end
    raise GraphQL::ExecutionError, "Anonymous assignments cannot be hidden by section" if assignment.anonymize_students?

    if sections.empty? || sections.count != input[:section_ids].size
      raise GraphQL::ExecutionError, "Invalid section ids"
    end

    visible_enrollments = course.apply_enrollment_visibility(course.student_enrollments, current_user, sections)

    submissions_scope = input[:graded_only] ? assignment.submissions.graded : assignment.submissions
    submissions_scope = submissions_scope.joins(user: :enrollments).merge(visible_enrollments)

    progress = course.progresses.new(tag: "hide_assignment_grades_for_sections")

    if progress.save
      progress.process_job(
        assignment,
        :hide_submissions,
        { preserve_method_args: true, priority: Delayed::HIGH_PRIORITY },
        progress:,
        submission_ids: submissions_scope.pluck(:id),
        skip_content_participation_refresh: false
      )

View on GitHub (pinned to 1c9f0bb801)