{"record":{"id":"a51f8e19479c7907","repo":"ankane/searchkick","slug":"unsupported-keywords-options-keys-map-inspect","errorCode":null,"errorMessage":"unsupported keywords: #{options.keys.map(&:inspect).join(\", \")}","messagePattern":"unsupported keywords: #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/searchkick/index.rb","lineNumber":239,"sourceCode":"        return reindex_records(object, method_name: method_name, ignore_missing: ignore_missing, **options)\n      end\n\n      if !object.respond_to?(:searchkick_klass)\n        raise Error, \"Cannot reindex object\"\n      end\n\n      scoped = Searchkick.relation?(object)\n      # call searchkick_klass for inheritance\n      relation = scoped ? object.all : Searchkick.scope(object.searchkick_klass).all\n\n      refresh = options.fetch(:refresh, !scoped)\n      options.delete(:refresh)\n\n      if method_name || (scoped && !full)\n        mode = options.delete(:mode) || :inline\n        scope = options.delete(:scope)\n        job_options = options.delete(:job_options)\n        raise ArgumentError, \"unsupported keywords: #{options.keys.map(&:inspect).join(\", \")}\" if options.any?\n\n        # import only\n        import_scope(relation, method_name: method_name, mode: mode, scope: scope, ignore_missing: ignore_missing, job_options: job_options)\n        self.refresh if refresh\n        true\n      else\n        async = options.delete(:async)\n        if async\n          if async.is_a?(Hash) && async[:wait]\n            Searchkick.warn \"async option is deprecated - use mode: :async, wait: true instead\"\n            options[:wait] = true unless options.key?(:wait)\n          else\n            Searchkick.warn \"async option is deprecated - use mode: :async instead\"\n          end\n          options[:mode] ||= :async\n        end\n\n        full_reindex(relation, **options)","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/ankane/searchkick/blob/93e901a75b11a25101668a616e006b158251b16e/lib/searchkick/index.rb#L221-L257","documentation":"When a where value falls through to a term filter, Searchkick checks that value.as_json is a scalar. If it is still an Enumerable (a Set, a custom object serializing to an array/hash, etc.), Elasticsearch could not term-match it, so Searchkick raises TypeError with the Active Record-style message \"can't cast Set\". Arrays are auto-converted to a terms (in) query earlier, which is why sets and other enumerables hit this instead.","triggerScenarios":"Product.search('*', where: {status: Set.new(['a', 'b'])}) - Sets are not Arrays so they skip the automatic {in: value} conversion; passing a Struct or any object whose as_json returns an Array/Hash as a term value.","commonSituations":"Using Set for tag/category filters; passing Money/Struct/value objects or ActionController::Parameters where a scalar is expected; params that arrive hash-like instead of as a plain value.","solutions":["Convert collections explicitly: where: {status: set.to_a} - Arrays become a terms/in query automatically","Or use the explicit operator: where: {status: {in: [...]}}","For custom value objects, pass the primitive (e.g. money.amount) instead of the wrapper"],"exampleFix":"# before\nProduct.search('*', where: {status: Set.new(['new', 'used'])})\n# => TypeError: can't cast Set\n\n# after\nProduct.search('*', where: {status: Set.new(['new', 'used']).to_a})","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def term_value(v)\n  v = v.to_a if v.is_a?(Set)\n  raise TypeError, \"can't cast #{v.class.name}\" if v.as_json.is_a?(Enumerable)\n  v\nend\n\nProduct.search('*', where: {status: term_value(input)})","tryCatchPattern":"begin\n  Product.search('*', where: filters)\nrescue TypeError => e\n  raise unless e.message.start_with?(\"can't cast\")\n  filters.each { |k, v| filters[k] = v.to_a if v.is_a?(Set) }\n  retry\nend","preventionTips":["Normalize Set/Struct/custom objects to scalars or plain Arrays before building where hashes","Convert Sets with .to_a so they become terms (in) queries","Keep value objects out of filters - pass .amount/.id primitives"],"tags":["searchkick","where","typeerror","type-cast","term-filter"],"backgroundTag":"type-cast-failed","analyzedSha":"93e901a75b11a25101668a616e006b158251b16e","analyzedAt":"2026-08-21T19:06:23.767Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}