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

  1. Fetch the current rule id via the allocationRules GraphQL query and confirm it is active before mutating
  2. If the rule is soft-deleted, restore it or create a new rule instead of updating
  3. Verify the id is the AllocationRule's GraphQL/legacy id for the correct course
  4. 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

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)