hibernate/hibernate-orm · error · QueryException

Incoming parameter position [{position}] is less than base [

Error message

Incoming parameter position [{position}] is less than base [1]

What it means

When ParameterRecognizerImpl recognizes a JPA ordinal parameter '?n', it rejects any position below the JPA base of 1 with a QueryException. In practice this catches '?0' (or programmatically supplied non-positive positions), since the parser only reaches this callback with a token of digits.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sql/internal/ParameterRecognizerImpl.java:168

		if ( parameterList == null ) {
			parameterList = new ArrayList<>();
		}

		parameterList.add( new ParameterOccurrence( parameter, sqlStringBuffer.length() ) );
		sqlStringBuffer.append( "?" );
	}

	@Override
	public void jpaPositionalParameter(int position, int sourcePosition) {
		if ( parameterStyle == null ) {
			parameterStyle = ParameterStyle.NAMED;
		}
		else if ( parameterStyle != ParameterStyle.NAMED ) {
			throw new ParameterRecognitionException( "Cannot mix parameter styles between JDBC-style, ordinal and named in the same query" );
		}

		if ( position < 1 ) {
			throw new QueryException( "Incoming parameter position [" + position + "] is less than base [1]" );
		}

		QueryParameterImplementor<?> parameter = null;

		if ( positionalQueryParameters == null ) {
			positionalQueryParameters = new HashMap<>();
		}
		else {
			parameter = positionalQueryParameters.get( position );
		}

		if ( parameter == null ) {
			parameter = QueryParameterPositionalImpl.fromNativeQuery( position );
			positionalQueryParameters.put( position, parameter );
		}

		if ( parameterList == null ) {
			parameterList = new ArrayList<>();

View on GitHub (pinned to fad1729dce)

Solutions

  1. Change the first label to ?1 and shift the rest accordingly.
  2. Fix the generator that produces labels from 0-based indices (use index + 1).
  3. Prefer named parameters to remove off-by-one label bugs entirely.

Example fix

-- before
select * from person where x = ?0

-- after
select * from person where x = ?1
Defensive patterns

Strategy: validation

Validate before calling

static void validateNoZeroLabels(String sql) {
    var m = java.util.regex.Pattern.compile("\\?(\\d+)").matcher(sql);
    while (m.find()) {
        int pos = Integer.parseInt(m.group(1));
        if (pos < 1) throw new IllegalArgumentException("Label ?" + pos + " is below the JPA base of 1");
    }
}

Try / catch

try { em.createNativeQuery(sql); } catch (org.hibernate.QueryException e) { /* if 'less than base [1]' bump ?0 to ?1 and shift the rest */ throw e; }

Prevention

When it happens

Trigger: A query string containing '?0', e.g. "... where x = ?0", parsed at query creation. Also possible when ordinal positions are generated programmatically from 0-based loop counters and injected into the SQL.

Common situations: Developers assuming 0-based parameter indexes (JDBC PreparedStatement uses 1-based too); code that builds labels from array indices; conversion from libraries where ?0 was tolerated.

Related errors


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