{"record":{"id":"a470bbbf40bb3329","repo":"instructure/canvas-lms","slug":"anonymous-assignments-cannot-be-posted-by-section","errorCode":null,"errorMessage":"Anonymous assignments cannot be posted by section","messagePattern":"Anonymous assignments cannot be posted by section","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/hide_assignment_grades.rb","lineNumber":47,"sourceCode":"  field :assignment, Types::AssignmentType, null: true\n  field :progress, Types::ProgressType, null: true\n  field :sections, [Types::SectionType], null: true\n\n  def resolve(input:)\n    begin\n      assignment = AbstractAssignment.find_assignment_or_peer_review(input[:assignment_id])\n      course = assignment.context\n      sections = input[:section_ids] ? course.course_sections.where(id: input[:section_ids]) : nil\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 hidden before grades are published\"\n    end\n    raise GraphQL::ExecutionError, \"Anonymous assignments cannot be posted by section\" if sections && assignment.anonymous_grading?\n\n    if input[:only_student_ids] && input[:skip_student_ids]\n      raise GraphQL::ExecutionError, I18n.t(\"{a} and {b} cannot be used together\", a: \"only_student_ids\", b: \"skip_student_ids\")\n    end\n\n    visible_enrollments = course.apply_enrollment_visibility(course.student_enrollments, current_user, sections)\n    visible_enrollments = visible_enrollments.where(user_id: input[:only_student_ids]) if input[:only_student_ids]\n    visible_enrollments = visible_enrollments.where.not(user_id: input[:skip_student_ids]) if input[:skip_student_ids]\n\n    submissions_scope = assignment.submissions.active.joins(user: :enrollments)\n    submissions_scope = course.apply_enrollment_visibility(submissions_scope, current_user).merge(visible_enrollments)\n    progress = course.progresses.new(tag: \"hide_assignment_grades\")\n\n    if progress.save\n      progress.process_job(\n        assignment,\n        :hide_submissions,\n        { preserve_method_args: true, priority: Delayed::HIGH_PRIORITY },","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/hide_assignment_grades.rb#L29-L65","documentation":"When sections are supplied, the mutation refuses to act on anonymously graded assignments (assignment.anonymous_grading? is true), because posting/hiding by section would deanonymize students by revealing which students belong to each section.","triggerScenarios":"Calling hideAssignmentGrades with a non-empty section_ids on an assignment created with anonymous grading (anonymous_grading enabled and assignment is anonymous).","commonSituations":"Teachers used to section-level posting trying it on an anonymized assignment; scripts that always pass section_ids copied from non-anonymous flows; UI not hiding section options for anonymous assignments.","solutions":["Hide/post grades for the whole assignment without section_ids (omit section_ids).","Turn off anonymous grading if section-level operations are truly required (only possible before submissions, per policy), or re-create the assignment without anonymity.","Gate the UI: disable section selection when assignment.anonymousGrading is true.","If only certain students should be affected, use only_student_ids/skip_student_ids instead of sections — anonymity of the mapping is preserved differently, verify policy allows it."],"exampleFix":"// before\nawait HideAssignmentGrades.mutate({ assignmentId, sectionIds });\n// after\nif (assignment.anonymousGrading) {\n  await HideAssignmentGrades.mutate({ assignmentId }); // no sections\n} else {\n  await HideAssignmentGrades.mutate({ assignmentId, sectionIds });\n}","handlingStrategy":"validation","validationCode":"if (assignment.anonymousGrading && sectionIds?.length) {\n  sectionIds = undefined; // whole-assignment operation instead\n}","typeGuard":"const sectionScopingAllowed = (a) => Boolean(a && !a.anonymousGrading && !a.anonymizeStudents);","tryCatchPattern":"try { await hideGrades({ assignmentId, sectionIds }); }\ncatch (e) {\n  if (String(e).includes('Anonymous assignments')) return hideGrades({ assignmentId });\n  throw e;\n}","preventionTips":["Disable section filters in UI for anonymous assignments","Audit scripts for hardcoded section_ids","Understand Canvas anonymity flags before building grade tooling","Test grade workflows with an anonymous assignment fixture"],"tags":["graphql","anonymous-grading","canvas-lms"],"backgroundTag":"unsupported-operation","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"}