{"record":{"id":"3b66657d36d19372","repo":"instructure/canvas-lms","slug":"missingrequiredtoolprofilevalueserror","errorCode":"MissingRequiredToolProfileValuesError","errorMessage":"Missing required values: %{missing_values}","messagePattern":"Missing required values: %(.+?)","errorType":"validation","errorClass":"MissingRequiredToolProfileValuesError","httpStatus":null,"severity":"error","filePath":"app/models/importers/tool_profile_importer.rb","lineNumber":65,"sourceCode":"        rescue MissingRequiredToolProfileValuesError => e\n          migration.add_import_warning(\"tool_profile\", tool_profile[\"resource_href\"], e)\n        end\n      end\n\n      private\n\n      def tease_out_required_values!(tool_profile)\n        values = {\n          vendor_code: tool_profile.dig(\"tool_profile\", \"product_instance\", \"product_info\", \"product_family\", \"vendor\", \"code\"),\n          product_code: tool_profile.dig(\"tool_profile\", \"product_instance\", \"product_info\", \"product_family\", \"code\"),\n          registration_url: tool_profile.dig(\"meta\", \"registration_url\"),\n          product_name: tool_profile.dig(\"tool_profile\", \"product_instance\", \"product_info\", \"product_name\", \"default_value\"),\n        }\n\n        missing_keys = values.select { |_, v| v.nil? }.keys\n\n        if missing_keys.present?\n          raise MissingRequiredToolProfileValuesError, I18n.t(\"Missing required values: %{missing_values}\", missing_values: missing_keys.join(\",\"))\n        else\n          values\n        end\n      end\n    end\n  end\nend\n","sourceCodeStart":47,"sourceCodeEnd":73,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/importers/tool_profile_importer.rb#L47-L73","documentation":"Importers::ToolProfileImporter.tease_out_required_values! extracts required LTI tool profile fields (e.g. product_name default_value) from imported JSON. If any required value is nil it raises MissingRequiredToolProfileValuesError listing the missing keys, via an I18n message interpolating %{missing_values}.","triggerScenarios":"Importing a tool profile migration whose JSON lacks required paths, e.g. tool_profile.product_instance.product_info.product_name.default_value absent or null.","commonSituations":"Hand-written or vendor-supplied LTI ToolProfile JSON missing default_value fields; schema version drift where keys moved or were renamed; partial exports.","solutions":["Fix the source JSON to include all required values.","Validate the tool profile against the LTI ToolProfile schema before import.","Use the error's listed keys to request corrected data from the vendor.","Provide defaults only if product rules allow it."],"exampleFix":"// before\n{\"tool_profile\":{\"product_instance\":{\"product_info\":{}}}}\n// after\n{\"tool_profile\":{\"product_instance\":{\"product_info\":{\"product_name\":{\"default_value\":\"My Tool\"}}}}}","handlingStrategy":"validation","validationCode":"required = %w[tool_profile.product_instance.product_info.product_name.default_value]\nmissing = required.select { |path| tool_profile.dig(*path.split(\".\")).nil? }\nraise \"missing: #{missing.join(\",\")}\" if missing.any?","typeGuard":null,"tryCatchPattern":"begin\n  Importers::ToolProfileImporter.process_migration(migration, tool_profile)\nrescue Importers::ToolProfileImporter::MissingRequiredToolProfileValuesError => e\n  report_import_failure(migration, e.message)\nend","preventionTips":["Schema-validate tool profile JSON before import","Request complete profiles from vendors","Keep a known-good tool profile fixture for tests"],"tags":["lti","importer","validation"],"backgroundTag":"missing-required-config-field","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"}