{"record":{"id":"4309d9f1b4ee3b86","repo":"instructure/canvas-lms","slug":"allocation-rule-not-found","errorCode":null,"errorMessage":"Allocation rule not found","messagePattern":"Allocation rule not found","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/delete_allocation_rule.rb","lineNumber":50,"sourceCode":"    verify_authorized_action!(assignment, :delete)\n    context[:deleted_models] ||= {}\n    context[:deleted_models][:allocation_rule] = record\n    record.destroy\n    {\n      allocation_rule_id: record.id\n    }\n  end\n\n  def self.allocation_rule_id_log_entry(_entry, context)\n    context[:deleted_models][:allocation_rule]\n  end\n\n  private\n\n  def get_allocation_rule(rule_id)\n    AllocationRule.active.find(rule_id)\n  rescue ActiveRecord::RecordNotFound\n    raise GraphQL::ExecutionError, I18n.t(\"Allocation rule not found\")\n  end\n\n  def validate_feature_flag!(course)\n    unless course.feature_enabled?(:peer_review_allocation_and_grading)\n      raise GraphQL::ExecutionError, I18n.t(\"peer_review_allocation_and_grading feature flag is not enabled for this course\")\n    end\n  end\nend\n","sourceCodeStart":32,"sourceCodeEnd":59,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/delete_allocation_rule.rb#L32-L59","documentation":"DeleteAllocationRule's get_allocation_rule does AllocationRule.active.find(rule_id) and rescues ActiveRecord::RecordNotFound, converting it to GraphQL::ExecutionError \"Allocation rule not found\". It fires when the given rule id doesn't match an active (non-deleted) AllocationRule.","triggerScenarios":"Calling deleteAllocationRule with an id that never existed, was already deleted (soft-deleted, so excluded by .active scope), or belongs to another course/shard; passing a relay/global id where a legacy numeric id is expected or vice versa.","commonSituations":"Double-delete from a UI retry after the first delete succeeded; stale list cache showing a deleted rule; wrong course context; id from a different environment.","solutions":["Query the course's allocationRules via GraphQL and delete only an id present in the active list.","Handle the already-deleted case idempotently on the client (treat the error as success if the rule is gone).","Verify the id format matches what the mutation expects (relay_or_legacy id).","Confirm you're operating in the correct course/shard context."],"exampleFix":"// before\ndeleteAllocationRule(input: { id: deletedRuleId })\n// after\nconst rule = course.allocationRules.find(r => r.id === ruleId)\nif (rule) deleteAllocationRule(input: { id: ruleId })","handlingStrategy":"validation","validationCode":"const rule = course.allocationRules?.nodes?.find(r => r._id === ruleId || r.id === ruleId)\nif (!rule) throw new SkipError('allocation rule not active')","typeGuard":"function isActiveRule(rules, id) { return (rules || []).some(r => String(r._id ?? r.id) === String(id)); }","tryCatchPattern":"try {\n  await deleteAllocationRule({ id: ruleId })\n} catch (e) {\n  if (e.message.includes('Allocation rule not found')) {\n    refetchRules(); // already gone, treat as success\n  } else throw e;\n}","preventionTips":["Drive delete UIs from a freshly refetched rule list.","Make deletes idempotent client-side.","Don't share rule ids across courses/environments."],"tags":["graphql","record-not-found","allocation-rule"],"backgroundTag":"record-not-found","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"}