dotnet/efcore · error · InvalidOperationException

Ordering based on scoring function is not supported inside

Error message

Ordering based on scoring function is not supported inside '{orderByDescending}'. Use '{orderBy}' instead.

What it means

ApplyOrdering in Cosmos SelectExpression throws when an ordering expression is a scoring function (IsScoringFunction, e.g. VectorDistance or FullTextScore) and IsAscending is false. Cosmos DB scoring orderings must be ascending; descending a score reverses its semantic and is rejected. The user must call OrderBy, not OrderByDescending, for scoring functions.

Solutions

  1. Use OrderBy instead of OrderByDescending for the scoring function.
  2. If you genuinely need inverse-ranked results, redesign the query or apply client-side reversal after materialization (without Skip/Take).

Example fix

// before
var q = db.Items
    .OrderByDescending(i => EF.Functions.VectorDistance(i.Embedding, query));

// after
var q = db.Items
    .OrderBy(i => EF.Functions.VectorDistance(i.Embedding, query));
Defensive patterns

Strategy: validation

Validate before calling

// Reject OrderByDescending over scoring functions at the query builder boundary.
static bool IsScoringExpression(Expression e) =>
    e is MethodCallExpression m && m.Method.Name is "VectorDistance" or "FullTextScore";

static bool IsValidOrdering(MethodCallExpression call) =>
    !(call.Method.Name == nameof(Queryable.OrderByDescending) && IsScoringExpression(((UnaryExpression)call.Arguments[1]).Operand));

Prevention

When it happens

Trigger: Queryable.OrderByDescending(EF.Functions.VectorDistance(...)) or OrderByDescending(EF.Functions.FullTextScore(...)).

Common situations: Attempting to retrieve least-relevant results by descending the score; copy-pasting an OrderByDescending pattern that worked for a property onto a vector/full-text score.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/06ea8fcc7ab421b8. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Cosmos/Query/Internal/Expressions/SelectExpression.cs:462

    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    public void ApplyOffset(SqlExpression sqlExpression)
        => Offset = sqlExpression;

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    public void ApplyOrdering(OrderingExpression orderingExpression)
    {
        if (orderingExpression is { Expression: SqlFunctionExpression { IsScoringFunction: true }, IsAscending: false })
        {
            throw new InvalidOperationException(
                CosmosStrings.OrderByDescendingScoringFunction(nameof(Queryable.OrderByDescending), nameof(Queryable.OrderBy)));
        }

        _orderings.Clear();
        _orderings.Add(orderingExpression);
    }

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    public void AppendOrdering(OrderingExpression orderingExpression)
    {
        if (_orderings.Count > 0)
        {
            var existingScoringFunctionOrdering = _orderings is [{ Expression: SqlFunctionExpression { IsScoringFunction: true } }];

View on GitHub (pinned to 3a2006ef56)