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

Moderated assignments must be manually posted until grades…

Error message

Moderated assignments must be manually posted until grades are released

What it means

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.

Solutions

  1. Leave the moderated assignment's post policy as post_manually=true until grades are published, then re-run the mutation after publishing grades
  2. Check assignment.moderated_grading? and assignment.grades_published? before calling the mutation and skip or defer automatic-posting requests for moderated, unpublished assignments
  3. If automatic posting is genuinely needed, first publish grades for the assignment (e.g. via ModerationGrades/final grades flow), then set post_manually=false
  4. If moderated grading was enabled unintentionally, disable moderated_grading on the assignment before changing the post policy

Example fix

// before: unconditional mutation call
setAssignmentPostPolicy(input: { assignmentId: id, postManually: false })

// after: guard client-side against moderated grading
const canAutoPost = !assignment.moderatedGrading || assignment.gradesPublished;
if (canAutoPost) {
  setAssignmentPostPolicy(input: { assignmentId: id, postManually: false });
}
Defensive patterns

Strategy: validation

Validate before calling

function canAutoPost(assignment) {
  if (assignment.anonymousGrading) return false; // different error, but also manual-only
  if (assignment.moderatedGrading && !assignment.gradesPublished) return false;
  return true;
}
if (postManually === false && !canAutoPost(assignment)) {
  throw new Error('Moderated assignments must stay manually posted until grades are released');
}

Type guard

const isPostableAssignment = (a) =>
  a != null && typeof a.id !== 'undefined' && !(a.moderatedGrading === true && a.gradesPublished === false);

Try / catch

try {
  await setAssignmentPostPolicy({ variables: { assignmentId, postManually } });
} catch (e) {
  if (e.message.includes('must be manually posted until grades are released')) {
    showBanner('Automatic posting is unavailable for moderated assignments until grades are released.');
  } else { throw e; }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at app/graphql/mutations/set_assignment_post_policy.rb:45

  argument :post_manually, Boolean, required: true

  field :post_policy, Types::PostPolicyType, null: true

  def resolve(input:)
    begin
      assignment = AbstractAssignment.find_assignment_or_peer_review(input[:assignment_id])
      course = assignment.context
    rescue ActiveRecord::RecordNotFound
      raise GraphQL::ExecutionError, "An assignment with that id does not exist"
    end

    verify_authorized_action!(course, :manage_grades)

    if input[:post_manually] == false
      raise GraphQL::ExecutionError, I18n.t("Anonymous assignments must be manually posted") if assignment.anonymous_grading?

      if assignment.moderated_grading? && !assignment.grades_published?
        raise GraphQL::ExecutionError, I18n.t("Moderated assignments must be manually posted until grades are released")
      end
    end

    assignment.ensure_post_policy(post_manually: input[:post_manually])

    if Account.site_admin.feature_enabled?(:scheduled_feedback_releases) && input[:post_manually] == true
      is_post_params_blank = input[:post_comments_at].blank? && input[:post_grades_at].blank?

      if !is_post_params_blank
        assignment.post_policy.create_or_update_scheduled_post(input[:post_comments_at], input[:post_grades_at])
      elsif assignment.post_policy.scheduled_post && is_post_params_blank
        assignment.post_policy.remove_scheduled_post
      end
    end

    { post_policy: assignment.post_policy }
  end

View on GitHub (pinned to 1c9f0bb801)