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
- Disable the contributing filter before deleting: session.disableFilter(filterName)
- Move the restriction into the custom SQL: bake the predicate into the @SQLDelete statement so no external fragment is needed
- Drop @Where/@WhereRestrict on that entity and apply the filtering at query level instead
- 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
- Do not combine @SQLDelete with @Where/@WhereRestrict on the same entity
- Bake every restriction directly into the custom delete SQL
- Disable session filters before deleting entities with custom SQL deletes
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
- Invalid attempt to apply where-filter on top of custom sql-d
- write expression must contain exactly one value placeholder
- Entity may not be null
- Couldn't find table reference
- Unable to locate parameter `%s.%s` for %s - %s : %s
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/1ce4aeab6da3163d.
Report an issue: GitHub.