{"record":{"id":"4fdfa4ca0edd56f3","repo":"instructure/canvas-lms","slug":"invalid-section-ids-post-assignment-grades-for-sections","errorCode":null,"errorMessage":"Invalid section ids","messagePattern":"Invalid section ids","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/post_assignment_grades_for_sections.rb","lineNumber":49,"sourceCode":"\n  def resolve(input:)\n    begin\n      assignment = AbstractAssignment.find_assignment_or_peer_review(input[:assignment_id])\n      course = assignment.context\n      sections = course.course_sections.where(id: input[:section_ids])\n    rescue ActiveRecord::RecordNotFound\n      raise GraphQL::ExecutionError, \"not found\"\n    end\n\n    verify_authorized_action!(assignment, :grade)\n\n    unless assignment.grades_published?\n      raise GraphQL::ExecutionError, \"Assignments under moderation cannot be posted by section before grades are published\"\n    end\n    raise GraphQL::ExecutionError, \"Anonymous assignments cannot be posted by section\" if assignment.anonymous_grading?\n\n    if sections.empty? || sections.count != input[:section_ids].size\n      raise GraphQL::ExecutionError, \"Invalid section ids\"\n    end\n\n    visible_enrollments = course.apply_enrollment_visibility(course.student_enrollments, current_user, sections)\n\n    submissions_scope = input[:graded_only] ? assignment.submissions.postable : assignment.submissions\n    submissions_scope = submissions_scope.joins(user: :enrollments).merge(visible_enrollments)\n    progress = course.progresses.new(tag: \"post_assignment_grades_for_sections\")\n\n    posting_params = {\n      graded_only: !!input[:graded_only],\n      section_names: sections&.pluck(:name)\n    }\n\n    if progress.save\n      progress.process_job(\n        assignment,\n        :post_submissions,\n        { preserve_method_args: true, priority: Delayed::HIGH_PRIORITY },","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/post_assignment_grades_for_sections.rb#L31-L67","documentation":"Raised in the PostAssignmentGradesForSections GraphQL mutation when the set of section records resolved from the caller-supplied section_ids does not match the input list. Either no sections were found, or some ids were invalid/duplicated/inaccessible to the course, so the count of loaded sections differs from input[:section_ids].size. Canvas aborts the post rather than posting to a partial set of sections.","triggerScenarios":"Calling mutation postAssignmentGradesForSections with section_ids that are empty, contain ids not belonging to the assignment's course, contain duplicates that dedupe on load, reference soft-deleted/inactive sections, or use a malformed id that resolves to no Section.","commonSituations":"Frontend caches stale section ids after a section is deleted or merged; caller passes GID vs numeric ids inconsistently; posting by section on a course whose sections changed since the UI loaded; passing ids from a different course.","solutions":["Verify every id in section_ids belongs to the assignment's course: course.sections.active.pluck(:id).include?(id)","Remove empty or duplicate entries from section_ids before calling the mutation","Ensure the assignment's grades are published and it is not anonymous (those raise sibling errors before this one)","Fetch current section ids from the course GraphQL query instead of cached client state"],"exampleFix":"// before\npostAssignmentGradesForSections(assignmentId, sectionIds: staleIds)\n// after\nconst ids = [...new Set(sections.filter(s => s.courseId === course.id).map(s => s.id))]\nif (ids.length) postAssignmentGradesForSections(assignmentId, sectionIds: ids)","handlingStrategy":"validation","validationCode":"const ids = [...new Set(sectionIds || [])]\nconst valid = ids.every(id => course.sections.active.some(s => s.id === id || s.legacyNodeId === id))\nif (!ids.length || !valid) throw new Error('Invalid section ids before mutation call')","typeGuard":"function hasValidSectionIds(sections, ids) {\n  return Array.isArray(ids) && ids.length > 0 && new Set(ids).size === ids.length &&\n    ids.every(id => sections.some(s => s.id === id))\n}","tryCatchPattern":"try {\n  await postAssignmentGradesForSections({ id, sectionIds })\n} catch (e) {\n  if (e.message.includes('Invalid section ids')) {\n    refetchSections(); notify('One or more sections are no longer available')\n  } else throw e\n}","preventionTips":["Always resolve section ids from a fresh course query, never cached state","Dedupe and filter empty ids before submission","Check grades published / anonymous grading preconditions first to hit clearer errors","Validate ids belong to the assignment's course"],"tags":["graphql","validation","course-sections"],"backgroundTag":"invalid-argument-value","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"}