hibernate/hibernate-orm · error · IllegalArgumentException

First result cannot be negative

Error message

First result cannot be negative

What it means

SelectionQueryImpl.setFirstResult checks the session is open and then requires startPosition >= 0, throwing IllegalArgumentException for any negative value. Negative offsets have no meaning in the generated pagination SQL (offset/limit), so they are rejected outright rather than clamped.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/internal/SelectionQueryImpl.java:423

	@Override
	@Nullable
	public Integer getFetchSize() {
		return getQueryOptions().getFetchSize();
	}

	@Override
	@Nonnull
	public SelectionQueryImplementor<R> setFetchSize(int fetchSize) {
		queryOptions.setFetchSize( fetchSize );
		return this;
	}

	@Override
	@Nonnull
	public SelectionQueryImplementor<R> setFirstResult(int startPosition) {
		session.checkOpen();
		if ( startPosition < 0 ) {
			throw new IllegalArgumentException( "First result cannot be negative" );
		}
		queryOptions.getLimit().setFirstRow( startPosition );
		return this;
	}

	@Override
	@Nonnull
	public SelectionQueryImplementor<R> setMaxResults(int maxResults) {
		if ( maxResults < 0 ) {
			throw new IllegalArgumentException( "Max results cannot be negative" );
		}
		session.checkOpen();
		queryOptions.getLimit().setMaxRows( maxResults );
		return this;
	}

	@Override
	public SelectionQueryImplementor<R> setPage(Page page) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Clamp the offset: setFirstResult(Math.max(0, offset)).
  2. Validate and normalize page/size at the controller boundary (page >= 1 or >= 0 consistently, size > 0).
  3. Do not use -1 as a sentinel for 'no offset'; use 0 or skip the call.

Example fix

// before
int page = 0; // user sent page=0 in a 1-based UI
q.setFirstResult((page - 1) * size); // -size -> throws

// after
int page = Math.max(1, requestedPage);
q.setFirstResult((page - 1) * size);
Defensive patterns

Strategy: validation

Validate before calling

static int safeFirstResult(long page, int size) {
    if (page < 1 || size < 1) throw new IllegalArgumentException("page >= 1 and size >= 1 required");
    return (int) Math.max(0, (page - 1) * size);
}

Prevention

When it happens

Trigger: Calling setFirstResult(-1) directly, or more often setFirstResult((page - 1) * size) with page=0 in a 1-based UI, or a user-supplied page parameter parsed without validation (e.g. ?page=-2).

Common situations: Web pagination controllers mixing 0-based and 1-based page indices; computed offsets underflowing to negative; using -1 as an 'unset' sentinel default that leaks into the call.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/7a40069fc6218fa5. Report an issue: GitHub.