{"record":{"id":"aabcce3e60899af9","repo":"instructure/canvas-lms","slug":"accessibility-categorybreakdownservice-dropping-unknown-rule","errorCode":null,"errorMessage":"[Accessibility::CategoryBreakdownService] dropping unknown rule_type=#{rule_type} count=#{count}","messagePattern":"\\[Accessibility::CategoryBreakdownService\\] dropping unknown rule_type=#(.+?) count=#(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"app/services/accessibility/category_breakdown_service.rb","lineNumber":47,"sourceCode":"  def initialize(course_ids:)\n    @course_ids = course_ids\n  end\n\n  # @return [Hash] { course_id => { category => { workflow_state => count } } }\n  # Unknown rule_types are dropped.\n  def call\n    return {} if @course_ids.blank?\n\n    rows = AccessibilityIssue\n           .where(course_id: @course_ids)\n           .group(:course_id, :rule_type, :workflow_state)\n           .count\n\n    result = {}\n    rows.each do |(course_id, rule_type, workflow_state), count|\n      category = Accessibility::Rule.category_for(rule_type)\n      if category.nil?\n        Rails.logger.warn(\n          \"[Accessibility::CategoryBreakdownService] dropping unknown rule_type=#{rule_type} count=#{count}\"\n        )\n        next\n      end\n\n      result[course_id] ||= {}\n      result[course_id][category] ||= {}\n      result[course_id][category][workflow_state.to_sym] =\n        (result[course_id][category][workflow_state.to_sym] || 0) + count\n    end\n\n    result\n  end\nend\n","sourceCodeStart":29,"sourceCodeEnd":62,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/services/accessibility/category_breakdown_service.rb#L29-L62","documentation":"Accessibility::CategoryBreakdownService#call aggregates accessibility issue counts per course grouped by rule_type, mapping each rule_type to a category via Accessibility::Rule.category_for. When a rule_type stored in the DB has no registered category (unknown/unregistered rule), it logs this warning and drops that row from the breakdown instead of crashing.","triggerScenarios":"The accessibility_cOURSE_workflow_states/issue data contains a rule_type that Accessibility::Rule.category_for doesn't recognize — typically after a rule was renamed/removed in code while old scanned rows persist, or a plugin-added rule is no longer loaded.","commonSituations":"Migrations renaming accessibility rules without backfilling existing scan rows; downgrading Canvas so new rule_types in the DB are unknown to the running code; disabled plugins that previously registered custom rules.","solutions":["Backfill/rename stale rule_type values in accessibility scan data to match Accessibility::Rule's current registry","Re-run accessibility scans so issues are stored with valid current rule_types","Register the missing rule in Accessibility::Rule (add a category mapping) if the rule should still exist","Check whether a plugin registering custom accessibility rules is disabled in this environment"],"exampleFix":"// before\ncategory = Accessibility::Rule.category_for(rule_type)\nif category.nil?\n  Rails.logger.warn(\"[Accessibility::CategoryBreakdownService] dropping unknown rule_type=#{rule_type} count=#{count}\")\n  next\nend\n\n// after: migrate stale data\n# data fix:\nAccessibilityIssue.where(rule_type: 'old_rule_name').update_all(rule_type: 'new_rule_name')","handlingStrategy":"fallback","validationCode":"unless Accessibility::Rule.category_for(rule_type)\n  Rails.logger.warn(\"unknown rule_type #{rule_type}; migrating data needed\")\nend","typeGuard":"def known_rule_type?(rule_type)\n  !Accessibility::Rule.category_for(rule_type).nil?\nend","tryCatchPattern":null,"preventionTips":["When renaming/removing accessibility rules, backfill rule_type in existing scan rows","Keep rule definitions and categories in a single authoritative registry","Re-scan courses after rule registry changes","Ensure plugins registering custom rules stay enabled in all environments"],"tags":["ruby","accessibility","data-migration","enum"],"backgroundTag":"unsupported-enum-value","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"}