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
- 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
- Clean up stale NotificationPolicy/CommunicationChannel records whose channel types no longer exist
- If a plugin or shard provides custom channels, ensure the code defining deliver_via_<type> is loaded in the delivering process
- 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
- Validate path_type against a supported-channel allowlist before creating messages
- Clean up stale communication channels / notification policies regularly
- Keep deliver_via_* methods and channel types in one registry so they can't drift apart
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
- assessor and assessee required
- association required
- can only forward one conversation at a time
- can't accept
- Can't update submission scores unless it's completed
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_targetsView on GitHub (pinned to 1c9f0bb801)