ankane/searchkick · error · Searchkick::Error
Unknown model for index: #{index}. Pass the `models` option
Error message
Unknown model for index: #{index}. Pass the `models` option to the search method. What it means
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.
Source
Thrown at lib/searchkick/results.rb:242
def with_hit_and_missing_records
@with_hit_and_missing_records ||= begin
missing_records = []
if options[:load]
grouped_hits = hits.group_by { |hit, _| hit["_index"] }
# determine models
index_models = {}
grouped_hits.each do |index, _|
models =
if @klass
[@klass]
else
index_alias = index.split("_")[0..-2].join("_")
Array((options[:index_mapping] || {})[index_alias])
end
raise Error, "Unknown model for index: #{index}. Pass the `models` option to the search method." unless models.any?
index_models[index] = models
end
# fetch results
results = {}
grouped_hits.each do |index, index_hits|
results[index] = {}
index_models[index].each do |model|
results[index].merge!(results_query(model, index_hits).to_a.index_by { |r| r.id.to_s })
end
end
# sort
results =
hits.map do |hit|
result = results[hit["_index"]][hit["_id"].to_s]
if result && !(options[:load].is_a?(Hash) && options[:load][:dumpable])
if (hit["highlight"] || options[:highlight]) && !result.respond_to?(:search_highlights)View on GitHub (pinned to 93e901a75b)
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)
Example fix
# before
Searchkick.search("milk") # searches "*,-.*"; hits cannot be mapped to models
# after
Searchkick.search("milk", models: [Product, Store])
# or, raw hits without DB hydration:
Searchkick.search("milk", models: [Product, Store], load: false) Defensive patterns
Strategy: validation
Validate before calling
def global_search(term, models:) raise ArgumentError, "models: is required for multi-index search" if models.blank? Searchkick.search(term, models: models) end
Try / catch
begin
results = Searchkick.search(term)
rescue Searchkick::Error => e
raise unless e.message.start_with?("Unknown model for index:")
results = Searchkick.search(term, load: false) # raw hits, no DB hydration needed
end Prevention
- 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
When it happens
Trigger: `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).
Common situations: 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.
Related errors
- Pass `scroll` option to the search method for scrolling
- Scroll id has expired
- Multiple clients found - set Searchkick.client_type = :elast
- No client found - install the `elasticsearch` or `opensearch
- Could not find class: #{class_name}
AI-assisted analysis of ankane/searchkick@93e901a75b (2026-08-21).
Data as JSON: /api/errors/872d6f6dd71b7b59.
Report an issue: GitHub.