instructure/canvas-lms · error · Lti::PlatformNotificationService::InvalidNoticeHandler

e.message

Error message

e.message

What it means

Lti::PlatformNotificationService.subscribe_tool_for_notice builds an Lti::NoticeHandler and calls handler.validate!. If ActiveRecord validation fails (RecordInvalid), the record's validation message is re-raised as Lti::PlatformNotificationService::InvalidNoticeHandler. The bracketed text is the raise expression; the real message is the model's 'Validation failed: ...' string.

Solutions

  1. Read the raised InvalidNoticeHandler message for the exact failing validation on Lti::NoticeHandler.
  2. Check for an existing handler for the same tool and notice_type and unsubscribe/update instead of creating a duplicate.
  3. Ensure tool is a persisted Lti::Tool with a valid id and max_batch_size is a positive integer.
  4. Fix the payload so it satisfies NoticeHandler model validations, then retry subscribe_tool_for_notice.

Example fix

# before
Lti::PlatformNotificationService.subscribe_tool_for_notice(tool:, notice_type: 'hello_world', max_batch_size: 0)
# after
Lti::PlatformNotificationService.subscribe_tool_for_notice(tool:, notice_type: Lti::Pns::NoticeTypes::HELLO_WORLD, max_batch_size: 1)
Defensive patterns

Strategy: validation

Validate before calling

existing = Lti::NoticeHandler.find_by(tool:, notice_type:)
raise 'duplicate subscription' if existing
raise ArgumentError, 'max_batch_size must be positive' if max_batch_size && max_batch_size < 1

Try / catch

begin
  Lti::PlatformNotificationService.subscribe_tool_for_notice(tool:, notice_type:, max_batch_size:)
rescue Lti::PlatformNotificationService::InvalidNoticeHandler => e
  render json: { error: e.message }, status: :unprocessable_entity
end

Prevention

When it happens

Trigger: Subscribing a tool to a notice type where the Lti::NoticeHandler fails model validation — duplicate handler for (tool, notice_type), blank tool or notice_type, invalid max_batch_size, or other NoticeHandler model constraints.

Common situations: Installing the same LTI 1.3 platform notification subscription twice; tool passed without being persisted/having an id; max_batch_size set below 1 or to a non-integer; notice_type typo not caught by the earlier model check.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at app/services/lti/platform_notification_service.rb:38

module Lti
  module PlatformNotificationService
    module_function

    class InvalidNoticeHandler < StandardError; end

    def subscribe_tool_for_notice(tool:, notice_type:, handler_url:, max_batch_size:)
      validate_notice_type!(notice_type)
      handler = tool.lti_notice_handlers.new(
        notice_type:,
        url: handler_url,
        account: tool.related_account,
        max_batch_size:
      )

      begin
        handler.validate!
      rescue ActiveRecord::RecordInvalid => e
        raise InvalidNoticeHandler, e.message
      end

      destroy_notice_handlers(tool:, notice_type:)
      handler.save!

      if notice_type == Lti::Pns::NoticeTypes::HELLO_WORLD
        send_notices(notice_handler: handler, builders: [Lti::Pns::LtiHelloWorldNoticeBuilder.new])
      end
      handler_api_json(handler:)
    end

    def unsubscribe_tool_for_notice(tool:, notice_type:)
      validate_notice_type!(notice_type)
      destroy_notice_handlers(tool:, notice_type:)
      empty_api_json(notice_type:)
    end

    # @return [Array<Hash>] list of notice handlers for the tool in api format

View on GitHub (pinned to 1c9f0bb801)