{"record":{"id":"b96ab1305f8ba2e2","repo":"instructure/canvas-lms","slug":"app-app-must-be-one-of-supported-apps-join","errorCode":null,"errorMessage":"app '#{app}' must be one of: #{SUPPORTED_APPS.join(\", \")}","messagePattern":"app '#(.+?)' must be one of: #(.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":400,"severity":"error","filePath":"app/controllers/microfrontends_release_tag_override_controller.rb","lineNumber":69,"sourceCode":"\n  private\n\n  def validate_environment\n    not_found unless Setting.get(\"allow_microfrontend_release_tag_override\", \"false\") == \"true\"\n  end\n\n  def validate_params!\n    override_params = params[:override]\n\n    unless override_params.respond_to?(:each)\n      raise ArgumentError, \"override parameter must be a hash\"\n    end\n\n    override_params.each do |app, assets_url|\n      next if assets_url.blank?\n\n      unless SUPPORTED_APPS.include?(app)\n        raise ArgumentError, \"app '#{app}' must be one of: #{SUPPORTED_APPS.join(\", \")}\"\n      end\n\n      begin\n        uri = URI.parse(assets_url)\n        unless ALLOWED_HOSTS.include?(uri.host)\n          raise ArgumentError, \"assets_url host for '#{app}' must be one of: #{ALLOWED_HOSTS.join(\", \")}\"\n        end\n      rescue URI::InvalidURIError\n        raise ArgumentError, \"assets_url for '#{app}' must be a valid URL\"\n      end\n    end\n  end\nend\n","sourceCodeStart":51,"sourceCodeEnd":83,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/controllers/microfrontends_release_tag_override_controller.rb#L51-L83","documentation":"Raised by validate_params! when an override entry's app key is not in SUPPORTED_APPS. Only allow-listed applications may have their release tag/assets_url overridden, so unknown app names are rejected as ArgumentError.","triggerScenarios":"POSTing params[:override] containing an app name not listed in SUPPORTED_APPS (typo, new app not yet allow-listed, wrong casing); iterating over config that includes internal app keys.","commonSituations":"Ops scripts overriding releases for a newly added microfrontend before SUPPORTED_APPS was updated; renaming apps in frontend config without syncing the controller's allow-list.","solutions":["Use an app name exactly matching one in SUPPORTED_APPS (check the controller constant)","Add the new app to SUPPORTED_APPS if it is a legitimate microfrontend","Fix casing/typos in the app key","Confirm blank assets_url entries are intentional (those are skipped) rather than masking the real app name"],"exampleFix":"// before\n{ override: { 'dashboard2': 'https://cdn.example.com' } }\n// after\n{ override: { 'k5': 'https://cdn.example.com' } } // k5 is in SUPPORTED_APPS","handlingStrategy":"validation","validationCode":"const SUPPORTED_APPS = ['k5','...'];\nfor (const app of Object.keys(override)) if (!SUPPORTED_APPS.includes(app)) throw new Error(`unsupported app ${app}`);","typeGuard":null,"tryCatchPattern":"begin\n  validate_params!\nrescue ArgumentError => e\n  render json: { error: e.message, supported: SUPPORTED_APPS }, status: :bad_request\nend","preventionTips":["Read SUPPORTED_APPS from source before overriding","Sync app renames between frontend config and allow-list","Centralize the allow-list to avoid drift"],"tags":["ruby","allowlist","validation"],"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"}