hibernate/hibernate-orm · error · IllegalArgumentException

Incorrect value for query hint: {hintName}

Error message

Incorrect value for query hint: {hintName}

What it means

Thrown by AbstractCommonQueryContract.applyHint when a recognized Hibernate query hint is given a value of the wrong Java type. The switch that dispatches hints (e.g. 'org.hibernate.cacheRegion' and 'org.hibernate.fetchProfile' cast value to String, boolean/integer hints convert via getBoolean/getInteger) throws ClassCastException on a bad type, which is caught at hibernate-core/src/main/java/org/hibernate/query/internal/AbstractCommonQueryContract.java:605 and rethrown as IllegalArgumentException with this message. The hint name is echoed but not the expected type, so you must check the hint's contract in org.hibernate.jpa.HibernateHints (or LegacySpecHints/SpecHints) to see what type it wants.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/internal/AbstractCommonQueryContract.java:606

				case HINT_FOLLOW_ON_LOCKING:
					applyFollowOnLockingHint( getBoolean( value ) );
					return true;
				case HINT_CALLABLE_FUNCTION:
					applyCallableFunctionHint( hintName, value );
					return true;
				case HINT_CALLABLE_FUNCTION_RETURN_TYPE:
					applyCallableFunctionTypeHint( hintName, value );
				default:
					if ( hintName.startsWith( HINT_NATIVE_LOCK_MODE ) ) {
						// out-of-date support for specifying alias-specific lockmodes
						applyLockModeHint( HINT_NATIVE_LOCK_MODE, value );
						return true;
					}
					return false;
			}
		}
		catch ( ClassCastException e ) {
			throw new IllegalArgumentException( "Incorrect value for query hint: " + hintName, e );
		}
	}

	protected void applyQueryPlanCachingHint(String hintName, Object value) {
		queryOptions.setQueryPlanCachingEnabled( getBoolean( value ) );
	}

	protected void applyReadOnlyHint(String hintName, Object value) {
		queryOptions.setReadOnly( getBoolean( value ) );
	}

	protected void applyFetchSizeHint(String hintName, Object value) {
		queryOptions.setFetchSize( getInteger( value ) );
	}

	protected void applyResultCachingHint(String hintName, Object value) {
		queryOptions.setResultCachingEnabled( getBoolean( value ) );
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Check the expected value type in the org.hibernate.jpa.HibernateHints javadoc for the exact hint key and pass that type (String for cacheRegion/fetchProfile, Boolean or String boolean for read-only/cacheable, Integer for fetchSize/timeout)
  2. Use the Hint constants (HibernateHints.HINT_*, SpecHints.HINT_SPEC_*) instead of hand-typed strings so the key maps to a documented contract
  3. If the value comes from configuration, convert it explicitly before setHint (e.g. String.valueOf(...), Boolean.parseBoolean(...))
  4. Wrap setHint calls that take dynamic values in try/catch IllegalArgumentException and log the hint name and value class for a clear failure message

Example fix

// before
Map<String, Object> hints = config.getHints();
for ( var e : hints.entrySet() ) query.setHint( e.getKey(), e.getValue() ); // ClassCastException -> Incorrect value for query hint: org.hibernate.fetchProfile

// after
query.setHint( HibernateHints.HINT_FETCH_PROFILE, "order-with-items" ); // String value
query.setHint( HibernateHints.HINT_READ_ONLY, Boolean.TRUE ); // boolean value
Defensive patterns

Strategy: validation

Validate before calling

Object v = hintValue;
boolean ok = switch ( hintKey ) {
    case HibernateHints.HINT_FETCH_PROFILE,
         HibernateHints.HINT_CACHE_REGION -> v instanceof String;
    case HibernateHints.HINT_READ_ONLY,
         HibernateHints.HINT_QUERY_PLAN_CACHEABLE -> v instanceof Boolean || v instanceof String;
    case HibernateHints.HINT_FETCH_SIZE -> v instanceof Integer || v instanceof String;
    default -> true;
};
if ( !ok ) throw new IllegalArgumentException( "Wrong type for hint " + hintKey + ": " + v.getClass() );
query.setHint( hintKey, v );

Type guard

static boolean isValidHintValue(String key, Object v) {
    return switch ( key ) {
        case HibernateHints.HINT_CACHE_REGION, HibernateHints.HINT_FETCH_PROFILE -> v instanceof String;
        case HibernateHints.HINT_FETCH_SIZE -> v instanceof Integer || v instanceof String;
        case HibernateHints.HINT_READ_ONLY -> v instanceof Boolean || v instanceof String;
        default -> true;
    };
}

Try / catch

try {
    query.setHint( hintKey, value );
} catch ( IllegalArgumentException e ) {
    throw new IllegalStateException( "Bad value for hint '" + hintKey + "': class=" + (value == null ? "null" : value.getClass().getName()), e );
}

Prevention

When it happens

Trigger: Calling query.setHint("org.hibernate.cacheRegion", someInteger) or setHint("org.hibernate.fetchProfile", Boolean.TRUE) — both handlers do (String) value. Passing a String where a Boolean/Integer-convertible value is expected for hints handled by getBoolean/getInteger can also surface as CCE only when conversion itself casts. Alias-specific lock hints like "org.hibernate.lockMode.someAlias" reaching applyLockModeHint with an unsupported object type instead goes to error 2364, not this one.

Common situations: Hints loaded from a properties/YAML file or framework layer (Spring Data @QueryHints, custom interceptors) where values arrive as strings or boxed numbers and are forwarded without conversion; copy-pasting hint code between native, HQL and procedure queries; upgrading Hibernate across 5.x→6.x→7.x where deprecated javax.* hint keys were re-routed to new handlers with stricter value types.

Related errors


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