{"record":{"id":"08424ccbb7ce2b48","repo":"instructure/canvas-lms","slug":"missing-required-parameter-param-name","errorCode":null,"errorMessage":"Missing required parameter: #{param_name}","messagePattern":"Missing required parameter: #(.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"app/models/lti/pns/lti_asset_processor_contribution_notice_builder.rb","lineNumber":54,"sourceCode":"      HIDDEN = \"Hidden\"\n\n      VALID_CONTRIBUTION_STATUSES = [\n        DRAFT,\n        SUBMITTED,\n        DELETED,\n        HIDDEN\n      ].freeze\n\n      def initialize(params)\n        validate_params!(params)\n        @params = params\n        ensure_lti_ids\n        super()\n      end\n\n      def validate_params!(params)\n        REQUIRED_PARAMS.each do |param_name|\n          raise ArgumentError, \"Missing required parameter: #{param_name}\" unless params[param_name]\n        end\n        params[:assets].each do |asset|\n          REQUIRED_ASSETS_PARAMS.each do |asset_param_name|\n            raise ArgumentError, \"Missing required asset parameter #{asset_param_name}\" unless asset[asset_param_name]\n          end\n        end\n        if params[:assets].any? && params[:asset_report_service_url].blank?\n          raise ArgumentError, \"Missing required parameter: asset_report_service_url when assets are present\"\n        end\n        unless VALID_CONTRIBUTION_STATUSES.include?(params[:contribution_status])\n          raise ArgumentError, \"Invalid contribution_status: #{params[:contribution_status]}. Must be one of: #{VALID_CONTRIBUTION_STATUSES.join(\", \")}\"\n        end\n      end\n\n      def notice_type\n        NoticeTypes::ASSET_PROCESSOR_CONTRIBUTION\n      end\n","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/lti/pns/lti_asset_processor_contribution_notice_builder.rb#L36-L72","documentation":"Lti::Pns::LtiAssetProcessorContributionNoticeBuilder#validate_params! iterates REQUIRED_PARAMS and raises ArgumentError for the first param_name whose value is falsy (nil/false) in the params hash passed to the builder's initialize.","triggerScenarios":"Instantiating the notice builder without one of the REQUIRED_PARAMS keys present (or set to nil/false) in the params hash.","commonSituations":"Callers (e.g. observer/asset processor notification pipelines) omitting fields after a refactor; nil values propagated from upstream queries; hash built dynamically with missing keys.","solutions":["Inspect REQUIRED_PARAMS in the builder and supply every listed key before constructing","Add a pre-build validation that checks each REQUIRED_PARAMS key is present in your params hash","Rescue ArgumentError at the call site and log which parameter was missing"],"exampleFix":"// before\nLti::Pns::LtiAssetProcessorContributionNoticeBuilder.new({ assets: [...] })\n// after\nparams = { assets: [...], context: ctx, ... }\nmissing = Lti::Pns::LtiAssetProcessorContributionNoticeBuilder::REQUIRED_PARAMS.reject { |p| params[p] }\nraise \"missing #{missing}\" unless missing.empty?\nLti::Pns::LtiAssetProcessorContributionNoticeBuilder.new(params)","handlingStrategy":"validation","validationCode":"missing = Lti::Pns::LtiAssetProcessorContributionNoticeBuilder::REQUIRED_PARAMS.reject { |k| params[k] }\nraise \"missing: #{missing}\" unless missing.empty?","typeGuard":null,"tryCatchPattern":"begin\n  Builder.new(params)\nrescue ArgumentError => e\n  Rails.logger.error(\"PNS builder: #{e.message}\")\nend","preventionTips":["Validate params against REQUIRED_PARAMS before construction","Symbolize incoming hashes","Add builder-level specs covering required params"],"tags":["lti","params-validation","push-notification"],"backgroundTag":"missing-required-argument","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"}