{"record":{"id":"ca07357b03fedaaa","repo":"instructure/canvas-lms","slug":"validation-failed-notice-type-unknown-must-be-one-of-lti-pns","errorCode":null,"errorMessage":"Validation failed: Notice type unknown, must be one of [#{Lti::Pns::NoticeTypes::ALL.join(\", \")}]","messagePattern":"Validation failed: Notice type unknown, must be one of \\[#(.+?)\\]","errorType":"validation","errorClass":"Lti::PlatformNotificationService::InvalidNoticeHandler","httpStatus":null,"severity":"error","filePath":"app/services/lti/platform_notification_service.rb","lineNumber":105,"sourceCode":"    def notify_tools(cet_id_or_ids:, builders:)\n      notice_type = get_notice_type(builders:)\n      Lti::NoticeHandler.active.where(notice_type:, context_external_tool_id: cet_id_or_ids).find_each do |notice_handler|\n        send_notices(notice_handler:, builders:)\n      end\n    end\n\n    def notify_asset_processor(asset_processor, *builders)\n      notice_type = get_notice_type(builders:)\n      Lti::NoticeHandler.active.where(notice_type:, context_external_tool_id: asset_processor.context_external_tool_id).find_each do |notice_handler|\n        send_notices(notice_handler:, builders:)\n      end\n    end\n\n    def validate_notice_type!(notice_type)\n      # This is also validated in the model, but we want to validate for\n      # unsubscribing and have a consistent error also for subscribing\n      unless Lti::Pns::NoticeTypes::ALL.include?(notice_type)\n        raise InvalidNoticeHandler, \"Validation failed: Notice type unknown, must be one of [#{Lti::Pns::NoticeTypes::ALL.join(\", \")}]\"\n      end\n    end\n    private_class_method :validate_notice_type!\n\n    def send_notices(notice_handler:, builders:)\n      builders.each_slice(notice_handler.max_batch_size || builders.length) do |batch|\n        send_notice_batch(notice_handler:, builders: batch)\n      end\n    end\n    private_class_method :send_notices\n\n    def send_notice_batch(notice_handler:, builders:)\n      tool = notice_handler.context_external_tool\n      global_id = generate_notification_uuid\n      notice_objects = builders.map { |builder| builder.build(tool) }\n      webhook_body = { notices: notice_objects }.to_json\n\n      log_info = builders.map { |builder| builder.info_log(tool) }","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/services/lti/platform_notification_service.rb#L87-L123","documentation":"validate_notice_type! checks the given notice_type against Lti::Pns::NoticeTypes::ALL before subscribing or unsubscribing, raising InvalidNoticeHandler with an explicit 'Notice type unknown' message. The model also validates this for subscribing, but this class-level check guarantees consistent errors for unsubscribe too.","triggerScenarios":"Calling subscribe_tool_for_notice or unsubscribe_tool_for_notice with a notice_type string not present in Lti::Pns::NoticeTypes::ALL (typo, wrong casing, deprecated/renamed notice type).","commonSituations":"LTI tool configuration referencing an old or renamed notification type; typos like 'HelloWorld' vs 'hello_world'; clients hardcoding notice types instead of using the NoticeTypes constants.","solutions":["Use a constant from Lti::Pns::NoticeTypes (e.g. NoticeTypes::HELLO_WORLD) instead of a raw string.","Check the allowed list via Lti::Pns::NoticeTypes::ALL and match casing exactly.","Update tool configuration/JSON to reference a currently supported notice type.","If a new notice type is genuinely needed, add it to Lti::Pns::NoticeTypes::ALL and its builders."],"exampleFix":"# before\nsubscribe_tool_for_notice(tool:, notice_type: 'HelloWorld')\n# after\nsubscribe_tool_for_notice(tool:, notice_type: Lti::Pns::NoticeTypes::HELLO_WORLD)","handlingStrategy":"validation","validationCode":"raise ArgumentError, \"unknown notice_type\" unless Lti::Pns::NoticeTypes::ALL.include?(notice_type)","typeGuard":null,"tryCatchPattern":"begin\n  Lti::PlatformNotificationService.unsubscribe_tool_for_notice(tool:, notice_type:)\nrescue Lti::PlatformNotificationService::InvalidNoticeHandler => e\n  render json: { error: e.message }, status: :bad_request\nend","preventionTips":["Always use Lti::Pns::NoticeTypes constants, never raw strings","Validate notice_type against NoticeTypes::ALL in controllers before the service call","Update tool configurations when notice types are renamed or removed","Handle both subscribe and unsubscribe paths with the same validation"],"tags":["ruby","lti","validation","enum"],"backgroundTag":"invalid-enum-value","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"}