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
- Call ToPageAsync directly on the EF Cosmos DbSet<T> or an IQueryable derived from it (where, orderBy, select keep it an EF queryable).
- 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().
- Remove any .AsEnumerable()/.ToList() that precedes the call; the EF provider must be reachable from the source passed in.
- 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
- Call ToPageAsync on a DbSet<T> or a query composed from it - not List<T>.AsQueryable().
- For tests, use an EF in-memory provider or a TestQueryProvider implementing IAsyncQueryProvider.
- Do not re-wrap EF queryables in custom IQueryables that drop the provider.
- Document paging entry points so callers always pass EF queryables.
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
- An Azure Cosmos DB container name is defined on entity type
- Async lambdas are not supported
- Azure Cosmos DB does not support synchronous I/O. Make sure…
- Azure Cosmos DB does not support synchronous I/O. Make sure…
- Azure Cosmos DB does not support synchronous I/O. Make sure…
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)