instructure/canvas-lms · error · ArgumentError

Broadcast Policy block not supplied for #

Error message

Broadcast Policy block not supplied for #{self.class}

What it means

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.

Solutions

  1. Add a broadcast_policy block to the model: broadcast_policy { policy(:name) { ... } }
  2. Check that the module/concern defining broadcast_policy is actually included and loaded
  3. Remove or guard the manual broadcast_notifications call for models without policies
  4. Ensure broadcast_policy_list is defined on self.class (not just the singleton/parent) after refactors

Example fix

// before
class Announcement < ActiveRecord::Base; include BroadcastPolicy::InstanceMethods; end
// after
class Announcement < ActiveRecord::Base
  include BroadcastPolicy::InstanceMethods
  broadcast_policy do
    policy(:create) { ... }
  end
end
Defensive patterns

Strategy: try-catch

Validate before calling

def has_broadcast_policies?(klass)
  klass.respond_to?(:broadcast_policy_list) && klass.broadcast_policy_list.present?
end

Try / catch

begin
  record.broadcast_notifications(prior_version)
rescue ArgumentError => e
  Rails.logger.warn("skipping broadcast: #{e.message}")
end

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/7296f513dcbcb7da. Report an issue: GitHub.

Appendix: source

Thrown at gems/broadcast_policy/lib/broadcast_policy/instance_methods.rb:86

          end
          @mutations_before_last_save = ActiveModel::AttributeMutationTracker.new(other_attributes)
          previously_new_record = @previously_new_record
          @previously_new_record = !new_record? && other.new_record?
        end
        yield
      ensure
        @changed_attributes = frd_changed_attributes
        @mutations_before_last_save = frd_mutations_before_last_save
        @previously_new_record = previously_new_record
      end
    end

    # This is called after_save, but you can call it manually to trigger
    # notifications. If you pass in a prior_version of self, its
    # attributes will be used to fake out the various _was/_changed?
    # helpers
    def broadcast_notifications(prior_version = nil)
      raise ArgumentError, "Broadcast Policy block not supplied for #{self.class}" unless self.class.broadcast_policy_list

      if prior_version
        with_changed_attributes_from(prior_version) do
          self.class.broadcast_policy_list.broadcast(self)
        end
      else
        self.class.broadcast_policy_list.broadcast(self)
      end
    end

    attr_accessor :skip_broadcasts

    def save_without_broadcasting
      @skip_broadcasts = true
      save
    ensure
      @skip_broadcasts = false
    end

View on GitHub (pinned to 1c9f0bb801)