dotnet/efcore · error · InvalidOperationException

The provider for the source 'IQueryable' doesn't implement…

Error message

The provider for the source 'IQueryable' doesn't implement 'IAsyncQueryProvider'. Only providers that implement 'IAsyncQueryProvider' can be used for Entity Framework asynchronous operations.

What it means

CosmosQueryableExtensions.ToPageAsync throws InvalidOperationException(CoreStrings.IQueryableProviderNotAsync) when source.Provider does not implement IAsyncQueryProvider. EF Core Cosmos requires the async query provider to translate and execute the paged query asynchronously; an IEnumerable-derived sequence, an in-memory List<T>.AsQueryable(), or a mock that returns a synchronous IQueryProvider will all fail this check.

Solutions

  1. Call ToPageAsync directly on the EF Cosmos DbSet<T> or an IQueryable derived from it (where, orderBy, select keep it an EF queryable).
  2. If you must unit-test paging, use the EF Core in-memory provider or a test double that implements IAsyncQueryProvider (e.g. TestQueryProvider from EF test infrastructure) - do not use List<T>.AsQueryable().
  3. Remove any .AsEnumerable()/.ToList() that precedes the call; the EF provider must be reachable from the source passed in.
  4. If you have a wrapper around IQueryable, expose the underlying EF queryable for paging operations rather than re-wrapping it.

Example fix

// before - throws: provider is EnumerableQuery, not IAsyncQueryProvider
var rows = await InMemoryList.AsQueryable()
    .ToPageAsync(pageSize: 50, continuationToken: token);

// after - use the EF DbSet directly
var rows = await dbContext.Documents
    .Where(d => d.PartitionKey == pk)
    .ToPageAsync(pageSize: 50, continuationToken: token);
Defensive patterns

Strategy: type-guard

Validate before calling

// Guard the call site so ToPageAsync is only invoked on EF queryables.
static async Task<CosmosPage<T>> PageOrThrow<T>(IQueryable<T> source, int size, string? token)
    where T : class
{
    if (source.Provider is not IAsyncQueryProvider)
        throw new ArgumentException("ToPageAsync requires an EF Cosmos queryable.", nameof(source));
    return await source.ToPageAsync(size, token);
}

Type guard

static bool SupportsAsyncPaging<T>(IQueryable<T> q) => q.Provider is IAsyncQueryProvider;

Try / catch

// Not generally recoverable; the fix is to pass a real EF queryable.
try { return await query.ToPageAsync(size, token); }
catch (InvalidOperationException ex) when (ex.Message.Contains("IAsyncQueryProvider"))
{ logger.PagingOnNonEfQuery(query.Expression.ToString()); throw; }

Prevention

When it happens

Trigger: Calling ToPageAsync on List<T>.AsQueryable(); passing a query built from an in-memory IEnumerable; using a mock IQueryable whose Provider is a plain EnumerableQuery; calling ToPageAsync on an IQueryable exposed by a non-EF data source; composing the query after .AsEnumerable() which breaks the EF expression tree.

Common situations: Unit tests using List<T>.AsQueryable() to fake the Cosmos query; wrapping an EF query in a custom IQueryable that does not forward the EF provider; calling ToPageAsync on the wrong queryable after the query was already materialized for transformation.

Related errors


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

Appendix: source

Thrown at src/EFCore.Cosmos/Extensions/CosmosQueryableExtensions.cs:249

    ///     An optional continuation token returned from a previous execution of this query via
    ///     <see cref="CosmosPage{T}.ContinuationToken" />. If <see langword="null" />, retrieves query results from the start.
    /// </param>
    /// <param name="pageSize">
    ///     The maximum number of results in the returned <see cref="CosmosPage{T}" />. The page may contain fewer results if the database
    ///     did not contain enough matching results.
    /// </param>
    /// <param name="responseContinuationTokenLimitInKb">Limits the length of continuation token in the query response.</param>
    /// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
    /// <returns>A <see cref="CosmosPage{T}" /> containing at most <paramref name="pageSize" /> results.</returns>
    [Experimental(EFDiagnostics.PagingExperimental)]
    public static Task<CosmosPage<TSource>> ToPageAsync<TSource>(
        this IQueryable<TSource> source,
        int pageSize,
        string? continuationToken,
        int? responseContinuationTokenLimitInKb = null,
        CancellationToken cancellationToken = default)
        => source.Provider is not IAsyncQueryProvider provider
            ? throw new InvalidOperationException(CoreStrings.IQueryableProviderNotAsync)
            : provider.ExecuteAsync<Task<CosmosPage<TSource>>>(
                Expression.Call(
                    instance: null,
                    method: new Func<IQueryable<TSource>, int, string?, int?, CancellationToken, Task<CosmosPage<TSource>>>(ToPageAsync)
                        .Method,
                    arguments:
                    [
                        source.Expression,
                        Expression.Constant(pageSize, typeof(int)),
                        Expression.Constant(continuationToken, typeof(string)),
                        Expression.Constant(responseContinuationTokenLimitInKb, typeof(int?)),
                        Expression.Constant(default(CancellationToken), typeof(CancellationToken))
                    ]),
                cancellationToken);
}

View on GitHub (pinned to 3a2006ef56)