dotnet/efcore · error · InvalidOperationException
Cosmos SQL does not allow Offset without Limit. Consider spe
Error message
Cosmos SQL does not allow Offset without Limit. Consider specifying a 'Take' operation on the query.
What it means
Thrown by CosmosQuerySqlGenerator when emitting OFFSET and selectExpression.Limit is null. Cosmos SQL (the provider's dialect) requires every OFFSET to be paired with a LIMIT, so when a query carries Skip without Take the generator refuses to synthesize an arbitrary limit. The TODO comment references issue #18923 for tracking.
Source
Thrown at src/EFCore.Cosmos/Query/Internal/CosmosQuerySqlGenerator.cs:440
if (selectExpression.Offset != null)
{
Visit(selectExpression.Offset);
}
else
{
_sqlBuilder.Append('0');
}
_sqlBuilder.Append(" LIMIT ");
if (selectExpression.Limit != null)
{
Visit(selectExpression.Limit);
}
else
{
// TODO: See Issue#18923
throw new InvalidOperationException(CosmosStrings.OffsetRequiresLimit);
}
}
return selectExpression;
}
/// <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>
protected virtual Expression VisitFromSql(FromSqlExpression fromSqlExpression)
{
var sql = fromSqlExpression.Sql;
string[] substitutions;
View on GitHub (pinned to dbf9771522)
Solutions
- Add a Take(pageSize) after every Skip so the query becomes Skip(n).Take(m).
- If you genuinely want all rows after an offset, pass a large explicit Take (e.g. int.MaxValue) — but prefer real pagination with a bounded page size.
Example fix
// before
var page = await db.Items
.OrderBy(x => x.Id)
.Skip(50)
.ToListAsync();
// after
var page = await db.Items
.OrderBy(x => x.Id)
.Skip(50)
.Take(25)
.ToListAsync(); Defensive patterns
Strategy: validation
Validate before calling
// Guard pagination helpers: require a page size whenever skip > 0
static IQueryable<T> Page<T>(IQueryable<T> q, int skip, int take)
{
if (skip > 0 && take <= 0) throw new ArgumentOutOfRangeException(nameof(take), "Cosmos requires Take when Skip is used.");
return q.Skip(skip).Take(take);
} Prevention
- Always pair Skip with Take in a single pagination helper so Skip-only is impossible.
- For Cosmos, prefer continuation-token / ORDER BY + WHERE key pagination over large offset values.
When it happens
Trigger: Calling .Skip(n) on a Cosmos query without a following .Take(m), e.g. db.Items.OrderBy(x => x.Id).Skip(50).ToListAsync().
Common situations: Pagination code that only skips (page-by-offset without page-size). Reusing a Skip-only helper built for SQL Server against the Cosmos provider.
Related errors
- Unhandled expression '{expression}' of type '{expressionType
- The LINQ expression '{expression}' could not be translated.
- Including navigation '{navigation}' is not supported as the
- UnhandledExpressionInVisitor
- The type '{givenType}' cannot be mapped as a dictionary beca
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/5df701b4737967d0.
Report an issue: GitHub.