{"record":{"id":"3b4e603fcf2dba8d","repo":"instructure/canvas-lms","slug":"anonymous-assignments-must-be-manually-posted","errorCode":null,"errorMessage":"Anonymous assignments must be manually posted","messagePattern":"Anonymous assignments must be manually posted","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/set_assignment_post_policy.rb","lineNumber":42,"sourceCode":"  argument :assignment_id, ID, required: true, prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func(\"Assignment\")\n  argument :post_comments_at, String, required: false\n  argument :post_grades_at, String, required: false\n  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","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/set_assignment_post_policy.rb#L24-L60","documentation":"SetAssignmentPostPolicy rejects `postManually: false` (i.e. automatic posting) when the assignment has anonymous grading enabled, raising the localized message \"Anonymous assignments must be manually posted\". The library enforces this because auto-releasing grades would unmask anonymous submissions; teachers must post manually once anonymity is handled.","triggerScenarios":"Calling setAssignmentPostPolicy with input.postManually == false on an assignment where anonymous_grading? is true (anonymous discussions, anonymously graded assignments), by a user who does hold manage_grades permission.","commonSituations":"Trying to switch an anonymous assignment back to automatic posting after enabling anonymity; scripts that uniformly set postManually: false across all assignments in a course; migrating post policies without checking assignment grading anonymity settings.","solutions":["Call the mutation with postManually: true for anonymous assignments.","Disable anonymous grading on the assignment first if automatic posting is truly required, then set postManually: false.","Filter bulk scripts: skip assignments where anonymousGrading is true (or anonymous grading is locked after submissions exist).","Note the related rule: moderated assignments must stay manual until grades are published — handle both conditions in automation."],"exampleFix":"// before\nsetAssignmentPostPolicy(input: { assignmentId: \"7\", postManually: false }) // anonymous assignment\n// after\nsetAssignmentPostPolicy(input: { assignmentId: \"7\", postManually: true })\n// or, only when anonymity is off:\n// if (!assignment.anonymousGrading) setAssignmentPostPolicy(input: { assignmentId: \"7\", postManually: false })","handlingStrategy":"validation","validationCode":"const a = await client.query({ query: ASSIGNMENT_QUERY, variables: { id: assignmentId } });\nconst assignment = a?.data?.legacyNode ?? a?.data?.assignment;\nif (assignment?.anonymousGrading && postManually === false) {\n  throw new Error('anonymous assignments must be posted manually');\n}","typeGuard":"function canAutoPost(assignment) { return !!assignment && !assignment.anonymousGrading && !(assignment.moderatedGrading && !assignment.gradesPublished); }","tryCatchPattern":"try {\n  await client.mutate({ mutation: SET_ASSIGNMENT_POST_POLICY, variables: { assignmentId, postManually } });\n} catch (e) {\n  if (e.graphQLErrors?.some(g => /manually posted/.test(g.message))) {\n    // fall back to postManually: true and surface the constraint to the user\n  } else { throw e; }\n}","preventionTips":["Check anonymousGrading before setting postManually: false","Also handle moderated assignments that are not grades-published","Centralize post-policy logic so bulk tools respect anonymity rules","Remember anonymity cannot be disabled once submissions exist in some cases — default to manual posting"],"tags":["graphql","anonymous-grading","post-policy","validation"],"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"}