hibernate/hibernate-orm · error · HibernateException

Invalid attempt to apply where-restriction on top of custom

Error message

Invalid attempt to apply where-restriction on top of custom sql-delete mapping : 

What it means

When an entity or collection delete is rendered from custom SQL (@SQLDelete), Hibernate must not append dynamic where fragments on top of it. TableDeleteBuilderStandard.setWhere throws HibernateException('Invalid attempt to apply where-restriction on top of custom sql-delete mapping') whenever the mutation details carry custom SQL and a non-null where fragment is applied.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/sql/model/ast/builder/TableDeleteBuilderStandard.java:90

		this.whereFragment = whereFragment;
	}

	public String getSqlComment() {
		return sqlComment;
	}

	public void setSqlComment(String sqlComment) {
		this.sqlComment = sqlComment;
	}

	public String getWhereFragment() {
		return whereFragment;
	}

	@Override
	public void setWhere(String fragment) {
		if ( mutationDetails.getCustomSql() != null && fragment != null ) {
			throw new HibernateException(
					"Invalid attempt to apply where-restriction on top of custom sql-delete mapping : " +
							getMutationTarget().getNavigableRole().getFullPath()
			);
		}
	}

	@Override
	public void addWhereFragment(String fragment) {
		if ( mutationDetails.getCustomSql() != null && fragment != null ) {
			throw new HibernateException(
					"Invalid attempt to apply where-filter on top of custom sql-delete mapping : " +
							getMutationTarget().getNavigableRole().getFullPath()
			);
		}
	}

	@Override
	public TableDelete buildMutation() {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Disable the contributing filter before deleting: session.disableFilter(filterName)
  2. Move the restriction into the custom SQL: bake the predicate into the @SQLDelete statement so no external fragment is needed
  3. Drop @Where/@WhereRestrict on that entity and apply the filtering at query level instead
  4. Delete via a bulk JPQL or native statement that bypasses the custom-SQL delete builder

Example fix

// before
@SQLDelete( sql = "UPDATE Employee SET active = false WHERE id = ?" )
@Where( clause = "active = true" ) // delete routes through setWhere -> throws

// after
@SQLDelete( sql = "UPDATE Employee SET active = false WHERE id = ? AND active = true" )
// no @Where on the entity; filter active rows in queries
Defensive patterns

Strategy: validation

Validate before calling

// entity uses @SQLDelete: make sure no where fragment will be applied
boolean customSqlDelete = entityType.isAffectedByCustomSql(); // or check mapping metadata
if ( customSqlDelete ) {
    for ( String f : enabledFilterNames( session ) ) session.disableFilter( f );
}

Prevention

When it happens

Trigger: Deleting an entity mapped with @SQLDelete while something contributes a where fragment: @Where/@WhereRestrict on the entity, an enabled session @Filter applying to deletes, or other restriction logic that normally gets appended to generated deletes.

Common situations: Soft-delete setups combining @SQLDelete with @Where-based filtering; session filters left enabled before delete operations; filters that apply to DELETE statements colliding with custom SQL.

Related errors


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