{"record":{"id":"3e4e04fc2a9dc153","repo":"ankane/searchkick","slug":"knn-requires-elasticsearch-8-6","errorCode":null,"errorMessage":"knn requires Elasticsearch 8.6+","messagePattern":"knn requires Elasticsearch 8\\.6\\+","errorType":"exception","errorClass":"Searchkick::Error","httpStatus":null,"severity":"error","filePath":"lib/searchkick/index_options.rb","lineNumber":177,"sourceCode":"        settings[:number_of_shards] = 1\n        settings[:number_of_replicas] = 0\n      end\n\n      if options[:similarity]\n        settings[:similarity] = {default: {type: options[:similarity]}}\n      end\n\n      settings[:index] = {\n        max_ngram_diff: 49,\n        max_shingle_diff: 4\n      }\n\n      if options[:knn]\n        unless Searchkick.knn_support?\n          if Searchkick.opensearch?\n            raise Error, \"knn requires OpenSearch 2.4+\"\n          else\n            raise Error, \"knn requires Elasticsearch 8.6+\"\n          end\n        end\n\n        if Searchkick.opensearch? && options[:knn].any? { |_, v| !v[:distance].nil? }\n          # only enable if doing approximate search\n          settings[:index][:knn] = true\n        end\n      end\n\n      add_synonyms(settings)\n      add_search_synonyms(settings)\n\n      if options[:special_characters] == false\n        settings[:analysis][:analyzer].each_value do |analyzer_settings|\n          analyzer_settings[:filter].reject! { |f| f == \"asciifolding\" }\n        end\n      end\n","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/ankane/searchkick/blob/93e901a75b11a25101668a616e006b158251b16e/lib/searchkick/index_options.rb#L159-L195","documentation":"In Searchkick.multi_search, per-query failures come back as error payloads inside the msearch response rather than exceptions; Results#hits (and everything built on it - results, with_hit, suggestions) then raises Error 'Query error - use the error method to view it'. Calling .error on the results object returns the underlying Elasticsearch/OpenSearch error (unknown field, bad mapping, knn on an unmapped vector field, etc.).","triggerScenarios":"Searchkick.multi_search([keyword_query, knn_query]) where one query is invalid - e.g. knn against a field never mapped as a vector, or aggs on a text field without fielddata - then calling .results/.hits on that query's result object.","commonSituations":"Hybrid keyword+vector search where the vector field was never declared in searchkick knn: options or not reindexed; adding a new agg/filter without reindexing; one bad query poisoning a batched msearch while others succeed.","solutions":["Inspect the failure first: results = Searchkick.multi_search([q1, q2]); pp results.first.error - then fix the query it reports","For unmapped vectors, declare knn: {embedding: {dimensions: ..., distance: ...}} in the model's searchkick options and reindex","In multi_search flows, branch on result.error before touching .results so one bad query does not crash the page"],"exampleFix":"# before\nq1, q2 = build_queries\nresults = Searchkick.multi_search([q1, q2])\nresults.first.results # => Searchkick::Error: Query error - use the error method to view it\n\n# after\nresults = Searchkick.multi_search([q1, q2])\nif (err = results.first.error)\n  Rails.logger.error(\"search failed: #{err}\")\n  results.first.results # avoid; handle or return fallback\nelse\n  results.first.results\nend","handlingStrategy":"validation","validationCode":"def safe_results(result)\n  raise Searchkick::Error, result.error if result.error\n  result.results\nend\n\nq1, q2 = build_queries\nSearchkick.multi_search([q1, q2]).each { |r| safe_results(r) }","typeGuard":"def query_failed?(results)\n  !results.error.nil?\nend","tryCatchPattern":"begin\n  results.first.hits\nrescue Searchkick::Error\n  err = results.first.error\n  Rails.logger.error(\"search query failed: #{err}\")\n  [] # graceful fallback for this leg of the multi_search\nend","preventionTips":["After every Searchkick.multi_search, branch on result.error before reading results","Reindex after changing mappings/knn options so queries match the index schema","Log the full error payload - it contains the exact Elasticsearch reason needed to fix the query"],"tags":["searchkick","multi-search","query-error","elasticsearch","error-handling"],"backgroundTag":"search-query-failed","analyzedSha":"93e901a75b11a25101668a616e006b158251b16e","analyzedAt":"2026-08-21T19:06:23.767Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}