instructure/canvas-lms · error · GraphQL::ExecutionError
Allocation rule not found
Error message
Allocation rule not found
What it means
UpdateAllocationRule#get_allocation_rule looks up an AllocationRule with AllocationRule.active.find(rule_id). ActiveRecord::RecordNotFound is rescued and re-raised as a GraphQL::ExecutionError with the message 'Allocation rule not found'. It is thrown when the id does not match an existing allocation rule, or when the rule exists but is no longer active (soft-deleted).
Solutions
- Fetch the current rule id via the allocationRules GraphQL query and confirm it is active before mutating
- If the rule is soft-deleted, restore it or create a new rule instead of updating
- Verify the id is the AllocationRule's GraphQL/legacy id for the correct course
- Retry with a valid active rule id
Example fix
// before
mutation { updateAllocationRule(input: {id: "123", mustReview: 1}) { ... } }
// after
// query first and use the returned active rule id
query { course(id: 1) { allocationRules { id } } }
mutation { updateAllocationRule(input: {id: "<valid-active-id>", mustReview: 1}) { ... } } Defensive patterns
Strategy: validation
Validate before calling
const rule = await canvasQuery(`query { course(id: $cid) { allocationRules { id } } }`, {cid});
if (!rule?.allocationRules?.some(r => r.id === inputId)) throw new Error(`Allocation rule ${inputId} is missing or inactive; refresh rule ids before updating`); Type guard
function isActiveRule(rule) { return rule != null && typeof rule.id === 'string' && rule.id.length > 0; } Try / catch
try {
await updateAllocationRule({ id });
} catch (e) {
if (/Allocation rule not found/.test(e.message)) {
// refresh ids / recreate rule
} else { throw e; }
} Prevention
- Always resolve rule ids from a fresh allocationRules query, never from cached data
- Remember the lookup is scoped to AllocationRule.active — deleted rules will not resolve
- Log the rule id and course context when this error occurs to catch cross-course id mixups
When it happens
Trigger: Calling the updateAllocationRule mutation with an id that (a) does not exist, (b) belongs to a deleted/inactive rule (find is scoped to AllocationRule.active), or (c) is a malformed id that cannot be resolved to a record.
Common situations: The rule was deleted by another user between listing and updating; the client cached an old rule id; passing a rule id from a different course/account root; typos or stale references in scripts hitting the GraphQL API.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/8d1f7195d8fe4d7f.
Report an issue: GitHub.
Appendix: source
Thrown at app/graphql/mutations/update_allocation_rule.rb:47
validate_feature_flag!(course)
verify_authorized_action!(assignment, :update)
validate_id_arrays!(input)
updated_rules = if input[:reciprocal]
update_reciprocal_rules(allocation_rule, input, assignment, course)
else
update_regular_rules(allocation_rule, input, assignment, course)
end
process_allocation_rules(updated_rules)
end
private
def get_allocation_rule(rule_id)
AllocationRule.active.find(rule_id)
rescue ActiveRecord::RecordNotFound
raise GraphQL::ExecutionError, I18n.t("Allocation rule not found")
end
def update_reciprocal_rules(original_rule, input, assignment, course)
shared_opts = {
must_review: input[:must_review],
review_permitted: input[:review_permitted],
applies_to_assessor: input[:applies_to_assessor]
}
assess_opts = {
assessor_id: input[:assessor_ids].first,
assessee_id: input[:assessee_ids].first,
}
updated_rule = update_rule_fields(original_rule, shared_opts.merge(assess_opts))
reciprocal_opts = {
assessor_id: input[:assessee_ids].first,
assessee_id: input[:assessor_ids].first,
}View on GitHub (pinned to 1c9f0bb801)