hibernate/hibernate-orm · error · IllegalArgumentException

Null value not allowed for multi-valued parameter '?{positio

Error message

Null value not allowed for multi-valued parameter '?{position}'

What it means

Positional twin of error 2374: in setParameter(int position, Object value), when the ordinal parameter allows multi-valued binding and multipleBinding(...) is true, a null value is rejected with IllegalArgumentException ('?position' formatted into the message) instead of being cast to Collection for setParameterList. As with the named variant, the current multipleBinding() implementation returns false for null (it requires value instanceof Collection), so this throw is a defensive guard for the rule 'multi-valued parameters may not be null' rather than the live path.

Source

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

			@Nonnull String name,
			@Nullable Instant value,
			@Nonnull TemporalType temporalType) {
		locateBinding( name ).setBindValue( value, temporalType );
		return this;
	}

	@Override
	@Nonnull
	public CommonQueryContractImplementor setParameter(int position, @Nullable Object value) {
		session.checkOpen( false );
		if ( value instanceof TypedParameterValue<?> typedParameterValue ) {
			setTypedParameter( position, typedParameterValue );
		}
		else {
			final var binding = getQueryParameterBindings().getBinding( position );
			if ( multipleBinding( binding.getQueryParameter(), value ) ) {
				if ( value == null ) {
					throw new IllegalArgumentException( "Null value not allowed for multi-valued parameter '?" + position + "'" );
				}
				setParameterList( position, (Collection<?>) value );
			}
			else {
				binding.setBindValue( value, resolveJdbcParameterTypeIfNecessary() );
			}
		}
		return this;
	}

	@Override
	@Nonnull
	public CommonQueryContractImplementor setParameters(@Nonnull Object... arguments) {
		final int parameterCount = getParameterMetadata().getOrdinalParameterLabels().size();
		if ( arguments.length != parameterCount ) {
			throw new IllegalArgumentException(
					"Received " + arguments.length + " arguments for "
							+ parameterCount + " positional parameters"

View on GitHub (pinned to fad1729dce)

Solutions

  1. Pass an empty collection (List.of()) instead of null for collection-typed positional parameters
  2. Use setParameterList(position, values) explicitly so intent is unambiguous
  3. Omit the IN predicate dynamically when the collection is absent rather than binding null

Example fix

// before
query.setParameter( 1, idsOrNull ); // null into multi-valued ?1

// after
query.setParameterList( 1, idsOrNull == null ? List.of() : idsOrNull );
Defensive patterns

Strategy: validation

Validate before calling

if ( value instanceof Collection<?> c ) {
    query.setParameterList( position, c );
} else if ( value == null && query.getParameterMetadata()
            .getQueryParameter( position ).allowsMultiValuedBinding() ) {
    query.setParameterList( position, List.of() );
} else {
    query.setParameter( position, value );
}

Prevention

When it happens

Trigger: The guarded scenario: query.setParameter(1, null) where ?1 participates in an IN expansion ('?1 in'-style or collection-typed parameter). Helper layers that forward varargs positions with possible nulls, e.g. setParameter(i+1, args[i]) with null elements for missing optional values.

Common situations: Dynamic filters using positional parameters with optional collections; vararg-driven binders receiving sparse arrays; refactors from named to positional parameters keeping null-when-absent logic.

Related errors


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