instructure/canvas-lms · error
Unsupported message type: #
Error message
Unsupported message type: #{message_type} What it means
Lti::LaunchServices#build_jwt_message switches on the message type to pick a payload generator on the adapter; any message_type outside the explicitly supported list falls through to a generic RuntimeError. This guards the LTI Advantage JWT message pipeline against message types Canvas cannot build.
Solutions
- Add a when branch for the new message type mapping to the matching adapter generator method.
- Verify the message_type passed to build_jwt_message equals one of the supported LtiAdvantage::Messages::*::MESSAGE_TYPE constants.
- If a new type is needed, extend the LTI adapter with the corresponding generate_post_payload_for_* method.
- Rescue in create_and_log_launch and return 422/400 for unsupported types instead of a 500.
Example fix
// before
raise "Unsupported message type: #{message_type}"
// after
when LtiAdvantage::Messages::LineItemCreateRequest::MESSAGE_TYPE
adapter.generate_post_payload_for_line_item
else
raise "Unsupported message type: #{message_type}" Defensive patterns
Strategy: validation
Validate before calling
SUPPORTED = LtiAdvantage::Messages.constants.map { |c| "LtiAdvantage::Messages::#{c}".constantize.try(:MESSAGE_TYPE) }
raise ArgumentError, message_type unless SUPPORTED.include?(message_type) Type guard
def supported_message_type?(type) [LtiAdvantage::Messages::ReportReviewRequest::MESSAGE_TYPE, LtiAdvantage::Messages::EulaRequest::MESSAGE_TYPE].include?(type) end
Try / catch
begin
build_jwt_message(message_type, ...)
rescue RuntimeError => e
raise UnsupportedMessageType, e.message if e.message.start_with?('Unsupported message type:')
raise
end Prevention
- Only pass MESSAGE_TYPE constants, never hand-written strings.
- When upgrading lti-advantage, audit new message types and add case branches.
- Register custom message types before requesting them.
- Fail fast with a typed error instead of the generic RuntimeError.
When it happens
Trigger: Calling create_and_log_launch with a message_type not in the case list (e.g. a custom or newly introduced LtiAdvantage::Messages::* type whose adapter generator branch was not added), or a mistyped/nil message_type string.
Common situations: Upgrading lti-advantage gem adds a new message type (e.g. a newer AGS/Proctoring type) before Canvas's launch service learns about it; plugins or custom code request an unregistered message type; typo in MESSAGE_TYPE constant.
Related errors
- Access token expired
- Access token invalid - signature likely incorrect
- assignment_invalid
- Assignment not configured for external tool launches
- Assignment not configured for launches with specified tool
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/74f5eacc201b0f2d.
Report an issue: GitHub.
Appendix: source
Thrown at app/controllers/lti/launch_services.rb:73
log_launch(
message_type:,
launch_type: log_launch_type,
launch_url: lti_launch.params["target_link_uri"]
)
lti_launch
end
def build_jwt_message(adapter, message_type)
case message_type
when LtiAdvantage::Messages::AssetProcessorSettingsRequest::MESSAGE_TYPE
adapter.generate_post_payload_for_asset_processor_settings
when LtiAdvantage::Messages::ReportReviewRequest::MESSAGE_TYPE
adapter.generate_post_payload_for_report_review
when LtiAdvantage::Messages::EulaRequest::MESSAGE_TYPE
adapter.generate_post_payload_for_eula
else
raise "Unsupported message type: #{message_type}"
end
end
def create_lti_adapter(return_url:, lti_launch:, opts: {}, expander_opts: {})
default_opts = {
domain: HostUrl.context_host(@domain_root_account, request.host)
}
Lti::LtiAdvantageAdapter.new(
tool:,
user: @current_user,
context:,
return_url:,
expander: create_variable_expander(lti_launch:, expander_opts:),
include_storage_target: !in_lti_mobile_webview?,
opts: default_opts.merge(opts)
)
endView on GitHub (pinned to 1c9f0bb801)