{"record":{"id":"5a9b94319b82dc44","repo":"litedb-org/LiteDB","slug":"similarity-threshold-must-be-a-valid-number","errorCode":null,"errorMessage":"Similarity threshold must be a valid number.","messagePattern":"Similarity threshold must be a valid number\\.","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"LiteDB/Client/Database/LiteQueryable.cs","lineNumber":244,"sourceCode":"\n            return new LiteQueryable<BsonDocument>(_engine, _mapper, _collection, _query);\n        }\n\n        /// <summary>\n        /// Project each document of resultset into a new document/value based on selector expression\n        /// </summary>\n        public ILiteQueryable<K> Select<K>(Expression<Func<T, K>> selector)\n        {\n            _query.Select = _mapper.GetExpression(selector);\n\n            return new LiteQueryable<K>(_engine, _mapper, _collection, _query);\n        }\n\n        private static void ValidateVectorArguments(float[] target, double maxDistance)\n        {\n            if (target == null || target.Length == 0) throw new ArgumentException(\"Target vector must be provided.\", nameof(target));\n            // Dot-product queries interpret \"maxDistance\" as a minimum similarity score and may therefore pass negative values.\n            if (double.IsNaN(maxDistance)) throw new ArgumentOutOfRangeException(nameof(maxDistance), \"Similarity threshold must be a valid number.\");\n        }\n\n        private static BsonExpression CreateVectorSimilarityFilter(BsonExpression fieldExpr, float[] target, double maxDistance)\n        {\n            if (fieldExpr == null) throw new ArgumentNullException(nameof(fieldExpr));\n\n            ValidateVectorArguments(target, maxDistance);\n\n            var targetArray = new BsonArray(target.Select(v => new BsonValue(v)));\n            return BsonExpression.Create($\"{fieldExpr.Source} VECTOR_SIM @0 <= @1\", targetArray, new BsonValue(maxDistance));\n        }\n\n        internal ILiteQueryable<T> VectorWhereNear(string vectorField, float[] target, double maxDistance)\n        {\n            if (string.IsNullOrWhiteSpace(vectorField)) throw new ArgumentNullException(nameof(vectorField));\n\n            var fieldExpr = BsonExpression.Create($\"$.{vectorField}\");\n            return this.VectorWhereNear(fieldExpr, target, maxDistance);","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/litedb-org/LiteDB/blob/f906a5f850678719e39a39a006cb66dcae563cfa/LiteDB/Client/Database/LiteQueryable.cs#L226-L262","documentation":"Thrown by ValidateVectorArguments when maxDistance is NaN. A NaN threshold cannot be compared and would make the VECTOR_SIM filter meaningless. Note the source comment: negative values are intentionally allowed because dot-product similarity treats maxDistance as a minimum score, so only NaN (and, in the target guard, null/empty) is rejected.","triggerScenarios":"Calling VectorWhereNear with double.NaN as the distance, e.g. VectorWhereNear(field, target, double.NaN). Common when the threshold is computed (e.g. 0.0 / 0.0) or read from a source that yields NaN.","commonSituations":"Computing a similarity threshold via division that can divide by zero, parsing a threshold from user input or config that fails to a NaN, or propagating an upstream NaN from a statistics calculation.","solutions":["Validate the threshold with double.IsNaN before calling and fall back to a sensible default (e.g. 0.5).","Use double.IsFinite if you also want to reject infinity, then clamp to a valid range.","Trace where NaN enters: typically a 0.0/0.0 division or an unset config value parsed as NaN."],"exampleFix":"// before\nvar q = col.Query().VectorWhereNear(\"$.embedding\", vec, computedThreshold);\n\n// after\nvar threshold = double.IsNaN(computedThreshold) ? 0.5 : computedThreshold;\nvar q = col.Query().VectorWhereNear(\"$.embedding\", vec, threshold);","handlingStrategy":"validation","validationCode":"var threshold = double.IsNaN(maxDistance) ? 0.5 : maxDistance;","typeGuard":"static bool IsValidThreshold(double d) => !double.IsNaN(d);","tryCatchPattern":null,"preventionTips":["Sanitize thresholds computed from divisions that can divide by zero.","Prefer double.IsFinite to also reject infinity when appropriate."],"tags":["vector","vector-search","argument-range","nan"],"backgroundTag":null,"analyzedSha":"f906a5f850678719e39a39a006cb66dcae563cfa","analyzedAt":"2026-08-13T21:56:30.148Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}