{"record":{"id":"ece17b1094eb97f6","repo":"instructure/canvas-lms","slug":"e-message","errorCode":null,"errorMessage":"e.message","messagePattern":"e\\.message","errorType":"validation","errorClass":"Lti::PlatformNotificationService::InvalidNoticeHandler","httpStatus":null,"severity":"error","filePath":"app/services/lti/platform_notification_service.rb","lineNumber":38,"sourceCode":"module Lti\n  module PlatformNotificationService\n    module_function\n\n    class InvalidNoticeHandler < StandardError; end\n\n    def subscribe_tool_for_notice(tool:, notice_type:, handler_url:, max_batch_size:)\n      validate_notice_type!(notice_type)\n      handler = tool.lti_notice_handlers.new(\n        notice_type:,\n        url: handler_url,\n        account: tool.related_account,\n        max_batch_size:\n      )\n\n      begin\n        handler.validate!\n      rescue ActiveRecord::RecordInvalid => e\n        raise InvalidNoticeHandler, e.message\n      end\n\n      destroy_notice_handlers(tool:, notice_type:)\n      handler.save!\n\n      if notice_type == Lti::Pns::NoticeTypes::HELLO_WORLD\n        send_notices(notice_handler: handler, builders: [Lti::Pns::LtiHelloWorldNoticeBuilder.new])\n      end\n      handler_api_json(handler:)\n    end\n\n    def unsubscribe_tool_for_notice(tool:, notice_type:)\n      validate_notice_type!(notice_type)\n      destroy_notice_handlers(tool:, notice_type:)\n      empty_api_json(notice_type:)\n    end\n\n    # @return [Array<Hash>] list of notice handlers for the tool in api format","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/services/lti/platform_notification_service.rb#L20-L56","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the raised InvalidNoticeHandler message for the exact failing validation on Lti::NoticeHandler.","Check for an existing handler for the same tool and notice_type and unsubscribe/update instead of creating a duplicate.","Ensure tool is a persisted Lti::Tool with a valid id and max_batch_size is a positive integer.","Fix the payload so it satisfies NoticeHandler model validations, then retry subscribe_tool_for_notice."],"exampleFix":"# before\nLti::PlatformNotificationService.subscribe_tool_for_notice(tool:, notice_type: 'hello_world', max_batch_size: 0)\n# after\nLti::PlatformNotificationService.subscribe_tool_for_notice(tool:, notice_type: Lti::Pns::NoticeTypes::HELLO_WORLD, max_batch_size: 1)","handlingStrategy":"validation","validationCode":"existing = Lti::NoticeHandler.find_by(tool:, notice_type:)\nraise 'duplicate subscription' if existing\nraise ArgumentError, 'max_batch_size must be positive' if max_batch_size && max_batch_size < 1","typeGuard":null,"tryCatchPattern":"begin\n  Lti::PlatformNotificationService.subscribe_tool_for_notice(tool:, notice_type:, max_batch_size:)\nrescue Lti::PlatformNotificationService::InvalidNoticeHandler => e\n  render json: { error: e.message }, status: :unprocessable_entity\nend","preventionTips":["Check for an existing handler for (tool, notice_type) before subscribing","Ensure the tool is persisted with a valid id","Validate max_batch_size is a positive integer before the call","Keep notice_type values sourced from Lti::Pns::NoticeTypes constants"],"tags":["ruby","lti","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}