hibernate/hibernate-orm · error · IllegalArgumentException

ProcedureCall cannot be treated as MutationQuery

Error message

ProcedureCall cannot be treated as MutationQuery

What it means

The mutation counterpart of the same refusal: asMutationQuery() exists on the common query contract, but ProcedureCallImpl throws IllegalArgumentException because a stored-procedure call is executed via ProcedureCall.execute()/executeUpdate(), not converted into the SQM MutationQuery pipeline used for HQL/ Criteria DML.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureCallImpl.java:282

		throw new IllegalArgumentException( "ProcedureCall cannot be treated as SelectionQuery" );
	}

	@Override
	@Nonnull
	public <X> SelectionQueryImplementor<X> asSelectionQuery(EntityGraph<X> entityGraph) {
		throw new IllegalArgumentException( "ProcedureCall cannot be treated as SelectionQuery" );
	}

	@Override
	@Nonnull
	public <X> SelectionQueryImplementor<X> withResultSetMapping(@Nonnull jakarta.persistence.sql.ResultSetMapping<X> mapping) {
		throw new IllegalArgumentException( "ProcedureCall cannot be treated as SelectionQuery" );
	}

	@Override
	@Nonnull
	public MutationQueryImplementor<R> asMutationQuery() {
		throw new IllegalArgumentException( "ProcedureCall cannot be treated as MutationQuery" );
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Options
	@Override
	@Nonnull
	public ProcedureCallImplementor<R> setComment(@Nullable String comment) {
		checkNotClosed();
		super.setComment( comment );
		return this;
	}

	@Override
	@Nonnull
	public ProcedureCallImplementor<R> setQueryFlushMode(@Nonnull QueryFlushMode queryFlushMode) {
		checkNotClosed();
		super.setQueryFlushMode( queryFlushMode );
		return this;

View on GitHub (pinned to fad1729dce)

Solutions

  1. Call executeUpdate() directly on the ProcedureCall — it is supported there without conversion.
  2. Add an instanceof ProcedureCall branch to helpers that otherwise use asMutationQuery().
  3. Keep procedure-based writes on the StoredProcedureQuery API, separate from HQL/Criteria mutation flows.

Example fix

// before
query.asMutationQuery().executeUpdate(); // query is a ProcedureCall -> throws

// after
if (query instanceof ProcedureCall<?> proc) {
    proc.executeUpdate();
} else {
    query.asMutationQuery().executeUpdate();
}
Defensive patterns

Strategy: type-guard

Type guard

static boolean isProcedureCall(jakarta.persistence.Query q) {
    return q instanceof org.hibernate.procedure.ProcedureCall;
}

Try / catch

try {
    query.asMutationQuery().executeUpdate();
} catch (IllegalArgumentException e) {
    ((ProcedureCall<?>) query).executeUpdate(); // procedures execute directly
}

Prevention

When it happens

Trigger: Calling asMutationQuery() on a ProcedureCall (session.createStoredProcedureQuery(...).asMutationQuery()); shared helpers that convert every query to MutationQuery before calling executeUpdate().

Common situations: Generic write-path code that accepts Query and normalizes via asMutationQuery(); 6.5+ migrations of (MutationQuery) casts; DML wrappers intended to also cover procedures.

Related errors


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