hibernate/hibernate-orm · error · UnsupportedOperationException
Mutating table reference should be handled by the statement
Error message
Mutating table reference should be handled by the statement visitation
What it means
MutatingTableReference is the table reference inside insert/update/delete statements. Its accept() deliberately throws UnsupportedOperationException because mutation rendering must walk the whole statement (TableInsert/TableUpdate/TableDelete) so the walker sees parameters, optional-table handling and returning clauses in context. A generic SqlAstWalker cannot render a mutating table reference in isolation.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/sql/model/ast/MutatingTableReference.java:54
@Override
public String getIdentificationVariable() {
return null;
}
@Override
public String getTableId() {
return getTableName();
}
@Override
public boolean isOptional() {
return tableMapping.isOptional();
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
throw new UnsupportedOperationException( "Mutating table reference should be handled by the statement visitation" );
}
@Override
public Boolean visitAffectedTableNames(Function<String, Boolean> nameCollector) {
return nameCollector.apply( getTableName() );
}
@Override
public TableReference resolveTableReference(
NavigablePath navigablePath,
String tableExpression) {
if ( getTableName().equals( tableExpression ) ) {
return this;
}
throw new IllegalArgumentException(
String.format(
Locale.ROOT,View on GitHub (pinned to fad1729dce)
Solutions
- Visit the containing statement instead: tableInsert.accept(walker) / tableUpdate.accept(walker) - statement visitation handles its mutating table reference
- Special-case MutatingTableReference in your walker and route to the mutation statement
- Use visitAffectedTableNames(...) (already implemented) when you only need the affected table names
- Never route mutation ASTs through select-statement walkers
Example fix
// before mutatingTableReference.accept( genericWalker ); // throws // after mutationStatement.accept( walker ); // TableInsert/TableUpdate/TableDelete drives its own table reference
Defensive patterns
Strategy: validation
Validate before calling
if ( ref instanceof MutatingTableReference ) {
mutationStatement.accept( walker ); // statement drives its own table reference
} else {
ref.accept( walker );
} Type guard
boolean isMutatingReference(TableReference ref) {
return ref instanceof MutatingTableReference;
} Prevention
- Never call accept() on a MutatingTableReference - always visit the containing mutation statement
- Use visitAffectedTableNames() when only table names are needed
- Keep custom walkers separate for select vs mutation ASTs
When it happens
Trigger: Passing a MutatingTableReference to a generic AST walker - e.g. utilities that call accept() on every TableReference found in an AST that mixes selects and mutations; reusing a select-statement walker or analyzer over mutation statements.
Common situations: Custom dialect statement emitters and SQL renderers; AST analysis/visitation utilities that iterate table references without special-casing mutation statements; code written against select-only ASTs later pointed at mutations.
Related errors
- Could not find table group for: %s
- removeTableGroupJoin not supported by %s
- Table-expression (%s) did not match mutating table name - %s
- Property not among declared properties: " + property.getName
- Could not resolve ServiceRegistry
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/4101a5c3be225c93.
Report an issue: GitHub.