hibernate/hibernate-orm · error · IllegalArgumentException
Can't emulate offset fetch clause in subquery
Error message
Can't emulate offset fetch clause in subquery
What it means
SybaseASELegacySqlAstTranslator.visitOffsetFetchClause() throws IllegalArgumentException ('Can't emulate offset fetch clause in subquery') when a non-root QueryPart (a subquery) carries pagination that the dialect cannot emulate. Sybase ASE legacy only supports TOP N in subqueries, and only when the dialect version supports TOP at all: any OFFSET inside a subquery always throws, and a FETCH-only subquery throws when supportsTopClause() is false. Root-level pagination is handled by the emulated fetch/offset machinery and is unaffected.
Source
Thrown at hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacySqlAstTranslator.java:285
@Override
protected void visitValuesList(List<Values> valuesList) {
visitValuesListEmulateSelectUnion( valuesList );
}
@Override
public void visitValuesTableReference(ValuesTableReference tableReference) {
append( '(' );
visitValuesListEmulateSelectUnion( tableReference.getValuesList() );
append( ')' );
renderDerivedTableReferenceIdentificationVariable( tableReference );
}
@Override
public void visitOffsetFetchClause(QueryPart queryPart) {
assertRowsOnlyFetchClauseType( queryPart );
if ( !queryPart.isRoot() && queryPart.hasOffsetOrFetchClause() ) {
if ( queryPart.getFetchClauseExpression() != null && !supportsTopClause() || queryPart.getOffsetClauseExpression() != null ) {
throw new IllegalArgumentException( "Can't emulate offset fetch clause in subquery" );
}
}
}
@Override
protected void renderFetchExpression(Expression fetchExpression) {
if ( supportsParameterOffsetFetchExpression() ) {
super.renderFetchExpression( fetchExpression );
}
else {
renderExpressionAsLiteral( fetchExpression, getJdbcParameterBindings() );
}
}
@Override
protected void renderOffsetExpression(Expression offsetExpression) {
if ( supportsParameterOffsetFetchExpression() ) {
super.renderOffsetExpression( offsetExpression );View on GitHub (pinned to fad1729dce)
Solutions
- Move pagination to the outer query and use an inequality predicate for the subquery (seek style: 'where e.ts > (select max(...) ...)')
- Rewrite the subquery so it needs no OFFSET: filter with an IN list produced in Java, or use TOP-style logic the dialect supports
- If the failure comes from a FETCH-only subquery, raise the configured dialect version (supportsTopClause) so TOP-based emulation applies
- Compute the offset window in application code and pass concrete keys into the subquery
Example fix
// before - offset inside subquery (throws) select e from Event e where e.ts >= (select s.ts from Stamp s order by s.ts offset 10 rows fetch first 1 rows only) // after - paginate the outer query only select e from Event e where e.ts >= :threshold order by e.ts offset 10 rows fetch first 1 rows only
Defensive patterns
Strategy: try-catch
Validate before calling
void assertNoPaginationInSubquery(String hql) {
Matcher m = Pattern.compile('\\(\\s*select\\b(?:(?!\\)).)*?offset\\b', Pattern.CASE_INSENSITIVE | Pattern.DOTALL).matcher(hql);
if (m.find()) {
throw new IllegalArgumentException(
'Sybase ASE cannot emulate OFFSET inside a subquery; paginate the outer query');
}
} Try / catch
try {
return em.createQuery(hql).setFirstResult(offset).setMaxResults(limit).getResultList();
}
catch (IllegalArgumentException e) {
if (String.valueOf(e.getMessage()).contains('offset fetch clause in subquery')) {
// fall back to seek/keyset pagination without subquery offsets
return findByKeyset(lastSeenKey, limit);
}
throw e;
} Prevention
- Keep OFFSET/FETCH only at the root query level for Sybase ASE
- Prefer keyset (seek) predicates over offset subqueries for deep pagination
- Verify the configured dialect version supports TOP if FETCH-only subqueries are required
When it happens
Trigger: An HQL query containing a subquery with ORDER BY ... OFFSET ... FETCH FIRST, e.g. keyset/seek emulation like 'where (e.ts, e.id) > (select s.ts, s.id from S s order by ... offset :o rows fetch first :n rows only)'; criteria subqueries with setFirstResult/setMaxResults on Sybase ASE legacy.
Common situations: Pagination strategies that push OFFSET/FETCH into subqueries (seek pagination, 'select the Nth group' patterns); dialect minimum version configured below the release that supports TOP, making even FETCH-only subqueries fail; queries ported from databases that allow LIMIT in subqueries.
Related errors
- Can't emulate offset fetch clause in subquery
- Can't emulate offset clause in subquery
- Can't render offset and fetch clause for subquery
- Can't render offset and fetch clause for subquery
- Can't emulate offset clause in subquery
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/859d3b2f08f2bafc.
Report an issue: GitHub.