{"record":{"id":"64624afe142b1eaa","repo":"instructure/canvas-lms","slug":"search-type-must-be-one-of-search-types","errorCode":null,"errorMessage":"search_type must be one of #{SEARCH_TYPES}","messagePattern":"search_type must be one of #(.+?)","errorType":"validation","errorClass":"ParameterError","httpStatus":null,"severity":"error","filePath":"lib/user_list_v2.rb","lineNumber":49,"sourceCode":"  # - only search on particular columns\n  # - don't worry about whether we can create users or not: they either exist or they don't\n\n  SEARCH_TYPES = %w[unique_id sis_user_id cc_path].freeze\n\n  def initialize(list_in, root_account: Account.default, search_type: nil, current_user: nil, can_read_sis: false)\n    @errors = []\n    @addresses = []\n\n    @all_results = []\n    @resolved_results = []\n    @duplicate_results = []\n    @missing_results = []\n\n    @root_account = root_account\n    @current_user = current_user\n    @can_read_sis = can_read_sis\n    unless SEARCH_TYPES.include?(search_type)\n      raise ParameterError, \"search_type must be one of #{SEARCH_TYPES}\"\n    end\n\n    parse_list(list_in)\n\n    case search_type\n    when \"unique_id\"\n      resolve_by_unique_id\n    when \"sis_user_id\"\n      raise \"cannot read sis ids\" unless @can_read_sis\n\n      resolve_by_sis_user_id\n    when \"cc_path\"\n      resolve_by_cc_path\n    end\n    resolve_duplicates_and_missing\n  end\n\n  attr_reader :errors, :addresses, :resolved_results, :duplicate_results, :missing_results","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/lib/user_list_v2.rb#L31-L67","documentation":"UserListV2#initialize in lib/user_list_v.rb raises ParameterError when the search_type argument is not included in SEARCH_TYPES. The class only supports a fixed set of search strategies and fails fast at construction time on any other value.","triggerScenarios":"Calling UserListV2.new(list_in, search_type: ...) with a typo'd or unsupported search_type (anything not in SEARCH_TYPES, e.g. 'emails' instead of 'cc_path'/'unique_id' style values).","commonSituations":"Tool integrations passing user-supplied search type straight through without whitelisting; refactors renaming search types; typos in constants passed by controllers building user lists.","solutions":["Pass one of the values in UserListV2::SEARCH_TYPES (check the constant for the exact list)","Validate/normalize the search_type parameter before constructing UserListV2","Update the caller after a rename of a search type constant","Rescue ParameterError at the API/controller boundary to return a 400 with the allowed values"],"exampleFix":"// before\nUserListV2.new(list, search_type: 'email')\n// after\nUserListV2.new(list, search_type: UserListV2::SEARCH_TYPES.first) # e.g. a valid type like 'cc_path'","handlingStrategy":"validation","validationCode":"raise ParameterError unless UserListV2::SEARCH_TYPES.include?(search_type)","typeGuard":null,"tryCatchPattern":"begin\n  UserListV2.new(list, search_type: params[:search_type])\nrescue ParameterError => e\n  render json: {error: e.message, allowed: UserListV2::SEARCH_TYPES}, status: :bad_request\nend","preventionTips":["Reference the SEARCH_TYPES constant instead of string literals","Whitelist user-supplied search_type params","Rescue ParameterError at API boundaries with allowed values in the response"],"tags":["ruby","parameter-validation","user-search"],"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"}