{"record":{"id":"c6ba2e3232cb8141","repo":"instructure/canvas-lms","slug":"moderated-assignments-must-be-manually-posted-until-grades","errorCode":null,"errorMessage":"Moderated assignments must be manually posted until grades are released","messagePattern":"Moderated assignments must be manually posted until grades are released","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/set_assignment_post_policy.rb","lineNumber":45,"sourceCode":"  argument :post_manually, Boolean, required: true\n\n  field :post_policy, Types::PostPolicyType, 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    rescue ActiveRecord::RecordNotFound\n      raise GraphQL::ExecutionError, \"An assignment with that id does not exist\"\n    end\n\n    verify_authorized_action!(course, :manage_grades)\n\n    if input[:post_manually] == false\n      raise GraphQL::ExecutionError, I18n.t(\"Anonymous assignments must be manually posted\") if assignment.anonymous_grading?\n\n      if assignment.moderated_grading? && !assignment.grades_published?\n        raise GraphQL::ExecutionError, I18n.t(\"Moderated assignments must be manually posted until grades are released\")\n      end\n    end\n\n    assignment.ensure_post_policy(post_manually: input[:post_manually])\n\n    if Account.site_admin.feature_enabled?(:scheduled_feedback_releases) && input[:post_manually] == true\n      is_post_params_blank = input[:post_comments_at].blank? && input[:post_grades_at].blank?\n\n      if !is_post_params_blank\n        assignment.post_policy.create_or_update_scheduled_post(input[:post_comments_at], input[:post_grades_at])\n      elsif assignment.post_policy.scheduled_post && is_post_params_blank\n        assignment.post_policy.remove_scheduled_post\n      end\n    end\n\n    { post_policy: assignment.post_policy }\n  end\n","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/set_assignment_post_policy.rb#L27-L63","documentation":"This is a business-rule error raised by the SetAssignmentPostPolicy GraphQL mutation in Canvas LMS. It blocks an attempt to set post_manually=false (automatic posting) on a moderated assignment whose grades have not yet been published. Moderated grading requires a manual posting workflow so moderator-approved grades are not auto-released before final publication, hence the mutation refuses the request via GraphQL::ExecutionError.","triggerScenarios":"Calling the setAssignmentPostPolicy mutation with input.post_manually == false when (a) assignment.moderated_grading? is true and (b) assignment.grades_published? is false. Note the same block also raises a different message if assignment.anonymous_grading? is true.","commonSituations":"UI or integration scripts bulk-configuring post policies across course assignments; a teacher or admin turning on automatic posting for a moderated assignment before clicking 'Release grades'; automation importing assignments with moderated grading enabled and default post_manually=false settings.","solutions":["Leave the moderated assignment's post policy as post_manually=true until grades are published, then re-run the mutation after publishing grades","Check assignment.moderated_grading? and assignment.grades_published? before calling the mutation and skip or defer automatic-posting requests for moderated, unpublished assignments","If automatic posting is genuinely needed, first publish grades for the assignment (e.g. via ModerationGrades/final grades flow), then set post_manually=false","If moderated grading was enabled unintentionally, disable moderated_grading on the assignment before changing the post policy"],"exampleFix":"// before: unconditional mutation call\nsetAssignmentPostPolicy(input: { assignmentId: id, postManually: false })\n\n// after: guard client-side against moderated grading\nconst canAutoPost = !assignment.moderatedGrading || assignment.gradesPublished;\nif (canAutoPost) {\n  setAssignmentPostPolicy(input: { assignmentId: id, postManually: false });\n}","handlingStrategy":"validation","validationCode":"function canAutoPost(assignment) {\n  if (assignment.anonymousGrading) return false; // different error, but also manual-only\n  if (assignment.moderatedGrading && !assignment.gradesPublished) return false;\n  return true;\n}\nif (postManually === false && !canAutoPost(assignment)) {\n  throw new Error('Moderated assignments must stay manually posted until grades are released');\n}","typeGuard":"const isPostableAssignment = (a) =>\n  a != null && typeof a.id !== 'undefined' && !(a.moderatedGrading === true && a.gradesPublished === false);","tryCatchPattern":"try {\n  await setAssignmentPostPolicy({ variables: { assignmentId, postManually } });\n} catch (e) {\n  if (e.message.includes('must be manually posted until grades are released')) {\n    showBanner('Automatic posting is unavailable for moderated assignments until grades are released.');\n  } else { throw e; }\n}","preventionTips":["Check moderatedGrading and gradesPublished in the UI before offering the automatic-posting toggle","Default postManually to true for moderated and anonymous assignments","After publishing grades, refresh the assignment state before retrying the mutation","Wrap post-policy mutations in a shared helper that pre-validates assignment constraints"],"tags":["graphql","canvas-lms","moderated-grading","post-policy","business-rule"],"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"}