ankane/searchkick · error · ArgumentError

Unknown distance: #{distance}

Error message

Unknown distance: #{distance}

What it means

When building the OpenSearch `knn_vector` mapping, searchkick translates your `distance` string into an OpenSearch `space_type` via a fixed case statement: `"cosine"`→`cosinesimil`, `"euclidean"`→`l2`, `"inner_product"`→`innerproduct`. Any other value has no translation, so it raises `ArgumentError` rather than sending an invalid space_type to the server.

Source

Thrown at lib/searchkick/index_options.rb:459

            raise ArgumentError, "Must specify a distance for OpenSearch"
          end

          vector_options = {
            type: "knn_vector",
            dimension: knn_options[:dimensions]
          }

          if !distance.nil?
            space_type =
              case distance
              when "cosine"
                "cosinesimil"
              when "euclidean"
                "l2"
              when "inner_product"
                "innerproduct"
              else
                raise ArgumentError, "Unknown distance: #{distance}"
              end

            if !quantization.nil?
              raise ArgumentError, "Quantization not supported yet for OpenSearch"
            end

            vector_options[:method] = {
              name: "hnsw",
              space_type: space_type,
              engine: "lucene",
              parameters: knn_options.slice(:m, :ef_construction)
            }
          end

          mapping[field.to_s] = vector_options
        else
          vector_options = {
            type: "dense_vector",

View on GitHub (pinned to 93e901a75b)

Solutions

  1. Use one of the three accepted strings: `distance: "cosine"`, `distance: "euclidean"`, or `distance: "inner_product"`.
  2. Do not pass raw OpenSearch space_types or ES similarities — searchkick normalizes both platforms from the three abstract values.
  3. If you need an unsupported metric, drop to a hand-written `mappings:`/`merge_mappings` config for that field.
  4. Reindex after changing the knn config.

Example fix

# before
searchkick knn: {embedding: {dimensions: 768, distance: "cosinesimil"}}
# OpenSearch => ArgumentError: Unknown distance: cosinesimil

# after
searchkick knn: {embedding: {dimensions: 768, distance: "cosine"}}
Defensive patterns

Strategy: validation

Validate before calling

SUPPORTED_DISTANCES = %w[cosine euclidean inner_product].freeze
knn = {embedding: {dimensions: 768, distance: "cosine"}}
bad = knn.select { |_, o| !SUPPORTED_DISTANCES.include?(o[:distance]) }
raise ArgumentError, "unsupported distances: #{bad.keys.join(', ')}" if bad.any?
class Product < ApplicationRecord
  searchkick knn: knn
end

Type guard

def valid_knn_distance?(distance)
  %w[cosine euclidean inner_product].include?(distance)
end

Prevention

When it happens

Trigger: `searchkick knn: {embedding: {dimensions: 768, distance: "dot_product"}}` (or `"l2"`, `"cosinesimil"`, `"l2_norm"`, or any typo) on OpenSearch, followed by reindex/index creation.

Common situations: Copy-pasting OpenSearch's own space_type names (`cosinesimil`, `l2`, `innerproduct`) instead of searchkick's abstracted `distance` names; copy-pasting Elasticsearch similarity names (`l2_norm`, `max_inner_product`, `dot_product`) which the OpenSearch branch does not accept; using a vector-embedding vendor's default metric name verbatim.

Related errors


AI-assisted analysis of ankane/searchkick@93e901a75b (2026-08-21). Data as JSON: /api/errors/c8e157a2a8f64cbd. Report an issue: GitHub.