{"record":{"id":"872d6f6dd71b7b59","repo":"ankane/searchkick","slug":"unknown-model-for-index-index-pass-the-model","errorCode":null,"errorMessage":"Unknown model for index: #{index}. Pass the `models` option to the search method.","messagePattern":"Unknown model for index: #(.+?)\\. Pass the `models` option to the search method\\.","errorType":"exception","errorClass":"Searchkick::Error","httpStatus":null,"severity":"error","filePath":"lib/searchkick/results.rb","lineNumber":242,"sourceCode":"\n    def with_hit_and_missing_records\n      @with_hit_and_missing_records ||= begin\n        missing_records = []\n\n        if options[:load]\n          grouped_hits = hits.group_by { |hit, _| hit[\"_index\"] }\n\n          # determine models\n          index_models = {}\n          grouped_hits.each do |index, _|\n            models =\n              if @klass\n                [@klass]\n              else\n                index_alias = index.split(\"_\")[0..-2].join(\"_\")\n                Array((options[:index_mapping] || {})[index_alias])\n              end\n            raise Error, \"Unknown model for index: #{index}. Pass the `models` option to the search method.\" unless models.any?\n            index_models[index] = models\n          end\n\n          # fetch results\n          results = {}\n          grouped_hits.each do |index, index_hits|\n            results[index] = {}\n            index_models[index].each do |model|\n              results[index].merge!(results_query(model, index_hits).to_a.index_by { |r| r.id.to_s })\n            end\n          end\n\n          # sort\n          results =\n            hits.map do |hit|\n              result = results[hit[\"_index\"]][hit[\"_id\"].to_s]\n              if result && !(options[:load].is_a?(Hash) && options[:load][:dumpable])\n                if (hit[\"highlight\"] || options[:highlight]) && !result.respond_to?(:search_highlights)","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/ankane/searchkick/blob/93e901a75b11a25101668a616e006b158251b16e/lib/searchkick/results.rb#L224-L260","documentation":"When a search spans multiple indices, Searchkick must map each hit's `_index` back to ActiveRecord models to hydrate records. With no single `@klass`, it strips the timestamp suffix from the index name (results.rb:239) and looks the alias up in `options[:index_mapping]`, a mapping built only when a `models:` option was passed to the search (query.rb:70-76). An empty mapping or an alias missing from it raises `Unknown model for index: ...` before any records load.","triggerScenarios":"`Searchkick.search('milk')` with no `models:` - the query then targets the wildcard expression `\"*,-.*\"` (query.rb:87) so no mapping exists and any hit raises; passing a custom `index_name:` to the search whose indices are not registered models; a hit whose derived alias does not match any model in the `models:` list (e.g. unusual custom index names).","commonSituations":"Building site-wide search with Searchkick.search and forgetting the model list; searching alongside indices created outside Searchkick; changing index_prefix/suffix so derived aliases no longer match; upgrading to Searchkick 5+ where model-less searches hit the wildcard index expression.","solutions":["Pass the models explicitly: `Searchkick.search('milk', models: [Product, Store])` - this both targets the right indices and builds the alias-to-model mapping","If you only need raw hit metadata (ids, scores, highlights), pass `load: false` so no model resolution happens","If you set `index_name:` on the search call, replace it with `models:` or ensure every searched index belongs to a registered model","Keep the `models:` list complete when using inheritance, since one index can map to multiple child models (query.rb:73-75)"],"exampleFix":"# before\nSearchkick.search(\"milk\") # searches \"*,-.*\"; hits cannot be mapped to models\n\n# after\nSearchkick.search(\"milk\", models: [Product, Store])\n# or, raw hits without DB hydration:\nSearchkick.search(\"milk\", models: [Product, Store], load: false)","handlingStrategy":"validation","validationCode":"def global_search(term, models:)\n  raise ArgumentError, \"models: is required for multi-index search\" if models.blank?\n  Searchkick.search(term, models: models)\nend","typeGuard":null,"tryCatchPattern":"begin\n  results = Searchkick.search(term)\nrescue Searchkick::Error => e\n  raise unless e.message.start_with?(\"Unknown model for index:\")\n  results = Searchkick.search(term, load: false) # raw hits, no DB hydration needed\nend","preventionTips":["Never call Searchkick.search without the models: option","Centralize site-wide search in one wrapper that requires the model list","Use load: false for analytics-only queries that never touch the database"],"tags":["searchkick","elasticsearch","multi-index","models","ruby"],"backgroundTag":"multi-index-model-resolution","analyzedSha":"93e901a75b11a25101668a616e006b158251b16e","analyzedAt":"2026-08-21T19:06:23.767Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}