instructure/canvas-lms · error · GraphQL::ExecutionError
not found
Error message
not found
What it means
SelectProvisionalGrade raises "not found" when the active Assignment for assignment_id either does not exist or, more specifically, when `assignment.permits_moderation?(current_user)` returns false. Although the message says "not found", it is raised deliberately (not via rescue) as a GraphQL::ExecutionError to hide the existence of assignments the user may not moderate. The generic message is intentional so unauthorized users cannot probe assignment ids.
Solutions
- Confirm the current user is a final grader with 'Select final grade' moderation permission on that assignment before calling the mutation.
- Verify the assignment_id refers to an active (non-deleted, non-soft-deleted) assignment in the same course/shard.
- Check assignment state: moderated grading must be enabled and grades must not yet be published.
- If the message should distinguish permission vs missing records, add an explicit exists check plus a permission check with distinct messages server-side.
Example fix
// before (opaque failure)
selectProvisionalGrade(input: { assignmentId: "99", provisionalGradeId: "5" })
// after: verify moderation access first in a query
query {
assignment(id: "99") {
permissions { selectFinalGrade }
moderatedGrading { gradesPublished graderCount }
}
}
// then call the mutation as an authorized final grader Defensive patterns
Strategy: validation
Validate before calling
const perms = await client.query({ query: ASSIGNMENT_PERMS, variables: { id: assignmentId } });
const mg = perms?.data?.assignment?.moderatedGrading;
if (!perms?.data?.assignment) throw new Error('assignment not found');
if (mg?.gradesPublished) throw new Error('grades already published');
if (!perms.data.assignment.permissions?.selectFinalGrade) throw new Error('no moderation permission'); Type guard
function canModerate(assignment, userId) { return !!assignment && assignment.moderatedGrading?.finalGraderId != null && assignment.permissions?.selectFinalGrade === true; } Try / catch
try {
await client.mutate({ mutation: SELECT_PROVISIONAL_GRADE, variables });
} catch (e) {
if (e.graphQLErrors?.some(g => g.message === 'not found')) {
// re-check moderation rights and assignment existence; refresh UI state
} else { throw e; }
} Prevention
- Check permissions.selectFinalGrade before moderation mutations
- Confirm grades are not yet published
- Refresh assignment state after role or grader changes
- Treat 'not found' here as possibly permission-related, not just missing data
When it happens
Trigger: Calling selectProvisionalGrade with an assignment_id that is not an active assignment, or where the current_user is not a final grader / moderator on the assignment (permits_moderation? false), or the assignment has no moderation set / grades already published.
Common situations: A teacher whose moderation rights were removed after the UI was rendered; calling the mutation before being added as a final grader; using a deleted or unpublished assignment id; a student or observer id token attempting moderation; per-course permission changes after grades were published.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Allocation rule not found
- Assignment not found
- assignment not found: #
- assignment not found
- Assignments under moderation cannot be hidden before grades…
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/449814a08790a28d.
Report an issue: GitHub.
Appendix: source
Thrown at app/graphql/mutations/select_provisional_grade.rb:32
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
class Mutations::SelectProvisionalGrade < Mutations::BaseMutation
argument :assignment_id, ID, required: true, prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func("Assignment")
argument :provisional_grade_id, ID, required: true, prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func("ModeratedGrading::ProvisionalGrade")
field :provisional_grade, Types::ProvisionalGradeType, null: true
def resolve(input:) # rubocop:disable GraphQL/UnusedArgument
assignment_id = input[:assignment_id]
provisional_grade_id = input[:provisional_grade_id]
assignment = Assignment.active.find(assignment_id)
raise GraphQL::ExecutionError, "not found" unless assignment.permits_moderation?(current_user)
provisional_grade = assignment.provisional_grades.find(provisional_grade_id)
student = provisional_grade.submission.user
selection = ModeratedGrading::Selection.find_or_create_by!(assignment:, student:) do |s|
s.selected_provisional_grade_id = provisional_grade.id
end
selection.update!(selected_provisional_grade_id: provisional_grade.id) unless selection.selected_provisional_grade_id == provisional_grade.id
selection.create_moderation_event(current_user)
{ provisional_grade: }
rescue ActiveRecord::RecordNotFound
raise GraphQL::ExecutionError, "not found"
end
end
View on GitHub (pinned to 1c9f0bb801)