{"record":{"id":"46ebf83a0502206d","repo":"ankane/searchkick","slug":"redis-not-configured","errorCode":null,"errorMessage":"Redis not configured","messagePattern":"Redis not configured","errorType":"exception","errorClass":"Searchkick::Error","httpStatus":null,"severity":"error","filePath":"lib/searchkick.rb","lineNumber":259,"sourceCode":"        end\n        result\n      ensure\n        self.callbacks_value = previous_value\n      end\n    else\n      self.callbacks_value = value\n    end\n  end\n\n  def self.aws_credentials=(creds)\n    require \"faraday_middleware/aws_sigv4\"\n\n    @aws_credentials = creds\n    @client = nil # reset client\n  end\n\n  def self.reindex_status(index_name)\n    raise Error, \"Redis not configured\" unless redis\n\n    batches_left = Index.new(index_name).batches_left\n    {\n      completed: batches_left == 0,\n      batches_left: batches_left\n    }\n  end\n\n  def self.with_redis\n    if redis\n      if redis.respond_to?(:with)\n        redis.with do |r|\n          yield r\n        end\n      else\n        yield redis\n      end\n    end","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/ankane/searchkick/blob/93e901a75b11a25101668a616e006b158251b16e/lib/searchkick.rb#L241-L277","documentation":"Approximate kNN runs on a vector index (HNSW) that was created with the single distance metric declared in the model's searchkick options. Scoring that structure with a different metric would return wrong results, so Searchkick raises ArgumentError 'distance must match searchkick options for approximate search' unless the query distance equals the field's configured distance. Exact (brute-force script) search may use any supported metric.","triggerScenarios":"Model declares searchkick knn: {embedding: {dimensions: 768, distance: 'cosine'}}; query runs Product.search('*', knn: {field: :embedding, vector: vec, distance: 'euclidean', exact: false}) - mismatched distance under approximate mode raises.","commonSituations":"Experimenting with different similarity metrics per query without changing the mapping; changing the model's distance later while old call sites still hardcode the previous metric; copy-pasting a query from a project that used euclidean.","solutions":["Pass the same distance as the model mapping, or omit knn[:distance] so it falls back to the mapping value","If this query truly needs a different metric, pass exact: true (brute-force script scoring - slower but metric-independent)","If the whole dataset should switch metrics, change the model's knn distance and reindex so the vector index is rebuilt"],"exampleFix":"# before\nsearchkick knn: {embedding: {dimensions: 768, distance: 'cosine'}}\nProduct.search('*', knn: {field: :embedding, vector: vec, distance: 'euclidean'})\n# => ArgumentError: distance must match searchkick options for approximate search\n\n# after (inherit mapping distance)\nProduct.search('*', knn: {field: :embedding, vector: vec})\n# or force exact scoring with another metric\nProduct.search('*', knn: {field: :embedding, vector: vec, distance: 'euclidean', exact: true})","handlingStrategy":"validation","validationCode":"def safe_knn(vector:, field:, distance: nil)\n  mapped = Product.searchkick_options.dig(:knn, field)&.[](:distance)\n  distance ||= mapped or raise ArgumentError, 'distance required'\n  exact = distance != mapped # different metric only allowed via exact scoring\n  Product.search('*', knn: {field: field, vector: vector, distance: distance, exact: exact})\nend","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Single source of truth: read the distance from searchkick options instead of hardcoding per call site","If a query needs a different metric, set exact: true deliberately in one helper","Cover kNN queries with a test asserting the built params (Query#body) to catch metric drift"],"tags":["searchkick","knn","vector-search","distance-metric","config-mismatch"],"backgroundTag":"config-mismatch","analyzedSha":"93e901a75b11a25101668a616e006b158251b16e","analyzedAt":"2026-08-21T19:06:23.767Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}