instructure/canvas-lms · warning

Could not set delivery_method from #

Error message

Could not set delivery_method from #{path_type}

What it means

Message#deliver in Canvas resolves the delivery path by building a dynamic method name `deliver_via_#{path_type}` and checking it exists via respond_to?. If the message's path_type does not map to a known private delivery method (e.g. deliver_via_email, deliver_via_sms, deliver_via_twitter), it logs this warning and returns nil instead of delivering. It is a guard against unknown or removed notification policy delivery channel types.

Solutions

  1. Inspect the message's path_type (`Message.find(id).path_type`) and confirm it matches a supported channel type with a deliver_via_* method in app/models/message.rb
  2. Clean up stale NotificationPolicy/CommunicationChannel records whose channel types no longer exist
  3. If a plugin or shard provides custom channels, ensure the code defining deliver_via_<type> is loaded in the delivering process
  4. Add a mapping/allowlist for valid path_types before calling deliver so bad data is rejected upstream

Example fix

# before
delivery_method = :"deliver_via_#{path_type}"
if !delivery_method || !respond_to?(delivery_method, true)
  logger.warn("Could not set delivery_method from #{path_type}")
  return nil
end

# after: validate path_type up front
SUPPORTED_PATH_TYPES = %w[email sms push twitter].freeze
unless SUPPORTED_PATH_TYPES.include?(path_type.to_s)
  logger.warn("Could not set delivery_method from #{path_type}")
  return nil
end
send("deliver_via_#{path_type}")
Defensive patterns

Strategy: validation

Validate before calling

unless Message.respond_to?("deliver_via_#{path_type}", true)
  Rails.logger.warn("Unknown path_type #{path_type.inspect}; skipping delivery")
end

Type guard

def deliverable_path_type?(msg)
  pt = msg.path_type.to_s
  !pt.empty? && msg.respond_to?("deliver_via_#{pt}", true)
end

Prevention

When it happens

Trigger: A Message is delivered whose path_type (derived from the NotificationPolicy/communication channel type) is not one of the supported types with a corresponding deliver_via_* method — e.g. a stale/unknown channel type string, a typo'd path_type, or a delivery method removed in a refactor while old path_types remain in the DB. Note the code also checks `!delivery_method` which can only be truthy if path_type is nil.

Common situations: Legacy or orphaned communication channels / notification policies in the database referencing channel types no longer supported; plugins defining custom channels being disabled so deliver_via_* methods disappear; nil path_type on a message built without a proper path.

Related errors


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

Appendix: source

Thrown at app/models/message.rb:762

       (Notification.types_to_send_in_push.exclude?(notification_name) || !check_acct.enable_push_notifications?)
      return skip_and_cancel
    end

    InstStatsd::Statsd.distributed_increment("message.deliver.#{path_type}.#{notification_name}",
                                             short_stat: "message.deliver",
                                             tags: { path_type:, notification_name: })

    global_account_id = Shard.global_id_for(root_account_id, shard)
    InstStatsd::Statsd.increment("message.deliver.#{path_type}.#{global_account_id}",
                                 short_stat: "message.deliver_per_account",
                                 tags: { path_type: }.merge(Utils::InstStatsdUtils::Tags.tags_for(shard)))

    if check_acct.feature_enabled?(:notification_service)
      enqueue_to_sqs
    else
      delivery_method = :"deliver_via_#{path_type}"
      if !delivery_method || !respond_to?(delivery_method, true)
        logger.warn("Could not set delivery_method from #{path_type}")
        return nil
      end
      send(delivery_method)
    end
  end

  def skip_and_cancel
    InstStatsd::Statsd.distributed_increment("message.skip.#{path_type}.#{notification_name}",
                                             short_stat: "message.skip",
                                             tags: { path_type:, notification_name: })
    cancel
  end

  # Public: Enqueues a message to the notification_service's sqs queue
  #
  # Returns nothing
  def enqueue_to_sqs
    targets = notification_targets

View on GitHub (pinned to 1c9f0bb801)