{"record":{"id":"a4fc428e306953f0","repo":"ankane/searchkick","slug":"unknown-keywords-unknown-keywords-join","errorCode":null,"errorMessage":"unknown keywords: #{unknown_keywords.join(\", \")}","messagePattern":"unknown keywords: #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/searchkick/model.rb","lineNumber":19,"sourceCode":"module Searchkick\n  module Model\n    def searchkick(**options)\n      options = Searchkick.model_options.deep_merge(options)\n\n      if options[:conversions]\n        Searchkick.warn(\"The `conversions` option is deprecated in favor of `conversions_v2`, which provides much better search performance. Upgrade to `conversions_v2` or rename `conversions` to `conversions_v1`\")\n      end\n\n      if options.key?(:conversions_v1)\n        options[:conversions] = options.delete(:conversions_v1)\n      end\n\n      unknown_keywords = options.keys - [:_all, :_type, :batch_size, :callbacks, :callback_options, :case_sensitive, :conversions, :conversions_v2, :deep_paging, :default_fields,\n        :filterable, :geo_shape, :highlight, :ignore_above, :index_name, :index_prefix, :inheritance, :job_options, :knn, :language,\n        :locations, :mappings, :match, :max_result_window, :merge_mappings, :routing, :searchable, :search_synonyms, :settings, :similarity,\n        :special_characters, :stem, :stemmer, :stem_conversions, :stem_exclusion, :stemmer_override, :suggest, :synonyms, :text_end,\n        :text_middle, :text_start, :unscope, :word, :word_end, :word_middle, :word_start]\n      raise ArgumentError, \"unknown keywords: #{unknown_keywords.join(\", \")}\" if unknown_keywords.any?\n\n      raise \"Only call searchkick once per model\" if respond_to?(:searchkick_index)\n\n      Searchkick.models << self\n\n      options[:_type] ||= -> { searchkick_index.klass_document_type(self, true) }\n      options[:class_name] = model_name.name\n\n      callbacks = options.key?(:callbacks) ? options[:callbacks] : :inline\n      unless [:inline, true, false, :async, :queue].include?(callbacks)\n        raise ArgumentError, \"Invalid value for callbacks\"\n      end\n      callback_options = (options[:callback_options] || {}).dup\n      callback_options[:if] = [-> { Searchkick.callbacks?(default: callbacks) }, callback_options[:if]].compact.flatten(1)\n\n      base = self\n\n      mod = Module.new","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/ankane/searchkick/blob/93e901a75b11a25101668a616e006b158251b16e/lib/searchkick/model.rb#L1-L37","documentation":"The `searchkick` class macro validates its keyword arguments against a hardcoded allow-list (`:batch_size, :callbacks, :index_name, :knn, :language, ...` and ~45 more). Any key not on the list means you misspelled an option, passed a query-time option at model level, or used an option from a newer/older searchkick version — the unknown keys are collected and reported in one `ArgumentError` at class-load (boot) time.","triggerScenarios":"`searchkick feilds: [...]` (typo), `searchkick where: {...}` or `searchkick per_page: 20` (query-time options used at model level), or `searchkick scope_name: :foo` / any option added in a different searchkick version. Raises the moment the model class is loaded.","commonSituations":"Upgrading/downgrading the gem: an option that exists in v5 but not v4 (or vice versa) kills the app at boot; copying a config snippet from README HEAD while running an older gem; muscle-memory from other gems (elasticsearch-model, chewy) whose option names differ; silent Ruby behavior where a misspelled keyword becomes an unknown key rather than a syntax error.","solutions":["Read the listed keys and fix each typo against the allow-list in lib/searchkick/model.rb:13-16.","Move query-time options (`where`, `order`, `limit`, `per_page`, `fields`, `misspellings`, ...) out of the `searchkick` macro — they belong in `Model.search(...)` calls.","Check `Searchkick::VERSION` and the README section for your gem version to confirm the option exists; pin your Gemfile to the version whose docs you read.","After fixing, run a one-off boot (`rails runner 'puts Product'`) in CI so bad options fail the build, not production."],"exampleFix":"# before\nclass Product < ApplicationRecord\n  searchkick index_name: \"products\", feilds: [:name], per_page: 20\nend # => ArgumentError: unknown keywords: feilds, per_page\n\n# after\nclass Product < ApplicationRecord\n  searchkick index_name: \"products\", searchable: [:name]\nend\nProduct.search(\"milk\", per_page: 20)","handlingStrategy":"validation","validationCode":"# Fail at boot with your own message instead of the raw ArgumentError\nMODEL_OPTIONS = %i[index_name searchable filterable language callbacks batch_size knn].freeze\nopts = {index_name: \"products\", searchable: %i[name]}\nunknown = opts.keys - MODEL_OPTIONS\nraise ArgumentError, \"bad searchkick options: #{unknown.join(', ')}\" if unknown.any?\nclass Product < ApplicationRecord\n  searchkick **opts\nend","typeGuard":"def valid_searchkick_options?(opts)\n  allowed = %i[_all _type batch_size callbacks callback_options case_sensitive conversions conversions_v2 deep_paging default_fields filterable geo_shape highlight ignore_above index_name index_prefix inheritance job_options knn language locations mappings match max_result_window merge_mappings routing searchable search_synonyms settings similarity special_characters stem stemmer stem_conversions stem_exclusion stemmer_override suggest synonyms text_end text_middle text_start unscope word word_end word_middle word_start]\n  (opts.keys - allowed).empty?\nend","tryCatchPattern":null,"preventionTips":["Load one representative model in CI (`rails runner 'puts Product.name'`) so bad options break the build.","Keep model-level and query-level options in a cheat sheet; never mix them.","Lock the searchkick gem version in the Gemfile and read the README at that tag."],"tags":["searchkick","options","configuration","argumenterror","boot-error"],"backgroundTag":"unknown-option-keyword","analyzedSha":"93e901a75b11a25101668a616e006b158251b16e","analyzedAt":"2026-08-21T19:06:23.767Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}