{"record":{"id":"31c65b85e7eb18b8","repo":"instructure/canvas-lms","slug":"assignments-under-moderation-cannot-be-hidden-before-grades","errorCode":null,"errorMessage":"Assignments under moderation cannot be hidden before grades are published","messagePattern":"Assignments under moderation cannot be hidden before grades are published","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/hide_assignment_grades.rb","lineNumber":45,"sourceCode":"  argument :skip_student_ids, [ID], required: false, prepare: GraphQLHelpers.relay_or_legacy_ids_prepare_func(\"User\")\n\n  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,","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/hide_assignment_grades.rb#L27-L63","documentation":"The mutation blocks hiding assignment grades while the assignment is still in moderated grading and its grades are not yet published (grades_published? is false). This protects provisional grades from being posted/hidden before the moderator finalizes them.","triggerScenarios":"Calling hideAssignmentGrades on an assignment with moderated_grading enabled before a moderator has published final grades; calling it right after graders finish but before the publish action runs.","commonSituations":"Teacher with grade permissions (but not moderator role) attempting hide/post on a moderated assignment; automation that posts/hides grades immediately after submission upload on moderated assignments; UI state that doesn't reflect unpublished moderated grades.","solutions":["Wait for a moderator to publish grades (Assignment > Grade > 'Post Grades' / grades_published!); check assignment.grades_published_at first.","Complete moderated grading via the moderation page or ModerationSet/Assignment#moderated_grading workflow before hiding.","If the assignment shouldn't be moderated, disable moderated_grading (before grading) or use a non-moderated assignment.","Gate client UI: hide the 'Hide Grades' action unless gradesPublished is true in the assignment GraphQL data."],"exampleFix":"// before\nawait HideAssignmentGrades.mutate({ assignmentId });\n// after\nconst a = await fetchAssignment(assignmentId);\nif (a.moderatedGrading && !a.gradesPublished) throw new Error('Grades not yet published for moderated assignment');\nawait HideAssignmentGrades.mutate({ assignmentId });","handlingStrategy":"validation","validationCode":"const a = await fetchAssignment(assignmentId);\nif (a.moderatedGrading && !a.gradesPublished) throw new SkipError('Awaiting moderator grade publication');\nawait hideGrades({ assignmentId });","typeGuard":"const canHideGrades = (a) => Boolean(a && (!a.moderatedGrading || a.gradesPublished === true));","tryCatchPattern":"try { await hideGrades({ assignmentId }); }\ncatch (e) {\n  if (String(e).includes('grades are published')) { await notifyModerator(assignmentId); return; }\n  throw e;\n}","preventionTips":["Check gradesPublished in GraphQL assignment data before enabling hide/post UI","Subscribe to assignment updates to re-evaluate publication state","Document moderation workflow for teachers","Never schedule auto-hide jobs on moderated assignments without publication check"],"tags":["graphql","moderated-grading","canvas-lms","state-conflict"],"backgroundTag":"invalid-state-transition","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"}