{"record":{"id":"7296f513dcbcb7da","repo":"instructure/canvas-lms","slug":"broadcast-policy-block-not-supplied-for-self-class","errorCode":null,"errorMessage":"Broadcast Policy block not supplied for #{self.class}","messagePattern":"Broadcast Policy block not supplied for #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"gems/broadcast_policy/lib/broadcast_policy/instance_methods.rb","lineNumber":86,"sourceCode":"          end\n          @mutations_before_last_save = ActiveModel::AttributeMutationTracker.new(other_attributes)\n          previously_new_record = @previously_new_record\n          @previously_new_record = !new_record? && other.new_record?\n        end\n        yield\n      ensure\n        @changed_attributes = frd_changed_attributes\n        @mutations_before_last_save = frd_mutations_before_last_save\n        @previously_new_record = previously_new_record\n      end\n    end\n\n    # This is called after_save, but you can call it manually to trigger\n    # notifications. If you pass in a prior_version of self, its\n    # attributes will be used to fake out the various _was/_changed?\n    # helpers\n    def broadcast_notifications(prior_version = nil)\n      raise ArgumentError, \"Broadcast Policy block not supplied for #{self.class}\" unless self.class.broadcast_policy_list\n\n      if prior_version\n        with_changed_attributes_from(prior_version) do\n          self.class.broadcast_policy_list.broadcast(self)\n        end\n      else\n        self.class.broadcast_policy_list.broadcast(self)\n      end\n    end\n\n    attr_accessor :skip_broadcasts\n\n    def save_without_broadcasting\n      @skip_broadcasts = true\n      save\n    ensure\n      @skip_broadcasts = false\n    end","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/gems/broadcast_policy/lib/broadcast_policy/instance_methods.rb#L68-L104","documentation":"broadcast_notifications runs as an after_save hook (and can be called manually) to broadcast an object's Broadcast Policy notifications. It requires the class to have registered policies via broadcast_policy { ... }; if broadcast_policy_list is nil, no policy block was ever declared for that class, and it raises ArgumentError naming the class.","triggerScenarios":"Calling instance.broadcast_notifications (or triggering save on a model that includes BroadcastPolicy::InstanceMethods) where the class never declared a broadcast_policy block — or declared it in a concern/parent class that isn't loaded.","commonSituations":"Invoking the callback manually in a console or job on a model without policies; moving broadcast_policy declarations during a refactor so the including class lost them; mixing up the BroadcastPolicy gem's DSL with Canvas's older notification callbacks.","solutions":["Add a broadcast_policy block to the model: broadcast_policy { policy(:name) { ... } }","Check that the module/concern defining broadcast_policy is actually included and loaded","Remove or guard the manual broadcast_notifications call for models without policies","Ensure broadcast_policy_list is defined on self.class (not just the singleton/parent) after refactors"],"exampleFix":"// before\nclass Announcement < ActiveRecord::Base; include BroadcastPolicy::InstanceMethods; end\n// after\nclass Announcement < ActiveRecord::Base\n  include BroadcastPolicy::InstanceMethods\n  broadcast_policy do\n    policy(:create) { ... }\n  end\nend","handlingStrategy":"try-catch","validationCode":"def has_broadcast_policies?(klass)\n  klass.respond_to?(:broadcast_policy_list) && klass.broadcast_policy_list.present?\nend","typeGuard":null,"tryCatchPattern":"begin\n  record.broadcast_notifications(prior_version)\nrescue ArgumentError => e\n  Rails.logger.warn(\"skipping broadcast: #{e.message}\")\nend","preventionTips":["Declare a broadcast_policy block in every model that includes the concern","Centralize policy definitions in a shared concern","Test that save-time notifications don't raise for policy-less models"],"tags":["ruby","broadcast-policy","callbacks"],"backgroundTag":"missing-required-config","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"}