litedb-org/LiteDB · error · ArgumentOutOfRangeException

Similarity threshold must be a valid number.

Error message

Similarity threshold must be a valid number.

What it means

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.

Source

Thrown at LiteDB/Client/Database/LiteQueryable.cs:244

            return new LiteQueryable<BsonDocument>(_engine, _mapper, _collection, _query);
        }

        /// <summary>
        /// Project each document of resultset into a new document/value based on selector expression
        /// </summary>
        public ILiteQueryable<K> Select<K>(Expression<Func<T, K>> selector)
        {
            _query.Select = _mapper.GetExpression(selector);

            return new LiteQueryable<K>(_engine, _mapper, _collection, _query);
        }

        private static void ValidateVectorArguments(float[] target, double maxDistance)
        {
            if (target == null || target.Length == 0) throw new ArgumentException("Target vector must be provided.", nameof(target));
            // Dot-product queries interpret "maxDistance" as a minimum similarity score and may therefore pass negative values.
            if (double.IsNaN(maxDistance)) throw new ArgumentOutOfRangeException(nameof(maxDistance), "Similarity threshold must be a valid number.");
        }

        private static BsonExpression CreateVectorSimilarityFilter(BsonExpression fieldExpr, float[] target, double maxDistance)
        {
            if (fieldExpr == null) throw new ArgumentNullException(nameof(fieldExpr));

            ValidateVectorArguments(target, maxDistance);

            var targetArray = new BsonArray(target.Select(v => new BsonValue(v)));
            return BsonExpression.Create($"{fieldExpr.Source} VECTOR_SIM @0 <= @1", targetArray, new BsonValue(maxDistance));
        }

        internal ILiteQueryable<T> VectorWhereNear(string vectorField, float[] target, double maxDistance)
        {
            if (string.IsNullOrWhiteSpace(vectorField)) throw new ArgumentNullException(nameof(vectorField));

            var fieldExpr = BsonExpression.Create($"$.{vectorField}");
            return this.VectorWhereNear(fieldExpr, target, maxDistance);

View on GitHub (pinned to f906a5f850)

Solutions

  1. Validate the threshold with double.IsNaN before calling and fall back to a sensible default (e.g. 0.5).
  2. Use double.IsFinite if you also want to reject infinity, then clamp to a valid range.
  3. Trace where NaN enters: typically a 0.0/0.0 division or an unset config value parsed as NaN.

Example fix

// before
var q = col.Query().VectorWhereNear("$.embedding", vec, computedThreshold);

// after
var threshold = double.IsNaN(computedThreshold) ? 0.5 : computedThreshold;
var q = col.Query().VectorWhereNear("$.embedding", vec, threshold);
Defensive patterns

Strategy: validation

Validate before calling

var threshold = double.IsNaN(maxDistance) ? 0.5 : maxDistance;

Type guard

static bool IsValidThreshold(double d) => !double.IsNaN(d);

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of litedb-org/LiteDB@f906a5f850 (2026-08-13). Data as JSON: /api/errors/5a9b94319b82dc44. Report an issue: GitHub.