{"record":{"id":"12fd66fe2f2efb16","repo":"instructure/canvas-lms","slug":"e-message-assignment-maxgradersreachederror","errorCode":null,"errorMessage":"e.message (Assignment::MaxGradersReachedError)","messagePattern":"e\\.message \\(Assignment::MaxGradersReachedError\\)","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"warning","filePath":"app/graphql/mutations/save_rubric_assessment.rb","lineNumber":82,"sourceCode":"        assessment_type = assessment_details[:assessment_type]\n\n        unless association.user_can_assess_for?(assessor: current_user, assessee: user, assessment_type:)\n          raise GraphQL::ExecutionError, \"Not authorized to assess user\"\n        end\n\n        rubric_assessment = association.assess(\n          assessor: current_user,\n          user:,\n          artifact: asset,\n          assessment: assessment_details,\n          graded_anonymously: input[:graded_anonymously]\n        )\n\n        submission.reload\n        return { submission:, rubric_assessment:, rubric_association: association }\n      end\n    rescue Assignment::MaxGradersReachedError => e\n      raise GraphQL::ExecutionError, e.message\n    rescue Assignment::GradeError\n      raise GraphQL::ExecutionError, \"Assignment Grade Error\"\n    end\n  rescue ActiveRecord::RecordNotFound => e\n    raise GraphQL::ExecutionError, \"#{e.model} not found\"\n  end\n\n  def ensure_adjudication_possible(provisional:, association_object:, grader:, &)\n    # Non-assignment association objects crash if they're passed into this\n    # controller, since find_asset_for_assessment only exists on assignments.\n    # The check here thus serves only to make sure the crash doesn't happen on\n    # the call below.\n    return yield unless association_object.is_a?(Assignment)\n\n    association_object.ensure_grader_can_adjudicate(\n      grader:,\n      provisional:,\n      occupy_slot: true,","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/save_rubric_assessment.rb#L64-L100","documentation":"When a provisional grader submits a rubric assessment on a moderated assignment, the mutation claims a grading slot. Assignment::MaxGradersReachedError (rescued here) means no slots remain for this grader, and its message is surfaced as a GraphQL::ExecutionError.","triggerScenarios":"Moderated assignment with a limited number of provisional graders already full; a grader outside the allowed set attempts to grade; concurrent grading consumed the last slot between check and claim.","commonSituations":"Large moderated grading teams configured with fewer slots than graders; retries after failure re-claiming slots.","solutions":["Increase allowed provisional graders for the assignment or remove an inactive provisional grader.","Confirm the current_user is among the intended graders for this moderated assignment.","Retry later once another grader finishes and slots free up; surface the message to the end user."],"exampleFix":"// before\nrescue Assignment::MaxGradersReachedError => e\n  raise GraphQL::ExecutionError, e.message\n// after\nrescue Assignment::MaxGradersReachedError => e\n  raise GraphQL::ExecutionError, e.message.to_s.presence || 'Maximum number of graders reached for this assignment'","handlingStrategy":"retry","validationCode":"const graders = assignment.provisionalGraders?.length ?? 0\nif (graders >= assignment.allowedProvisionalGraders) showError('Grader slots full')","typeGuard":null,"tryCatchPattern":"try { await saveRubricAssessment(...) } catch (e) { if (e.message.includes('graders')) retryWithBackoff(3) }","preventionTips":["Show remaining grader slots in moderated grading UI","Limit concurrent grader sessions per assignment","Queue grader claims instead of direct attempts when slots are scarce"],"tags":["graphql","moderated-grading","rubric","concurrency"],"backgroundTag":"operation-not-supported","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"}