hibernate/hibernate-orm · error · IllegalStateException
Type for json_table function is already resolved. Mutation i
Error message
Type for json_table function is already resolved. Mutation is not allowed anymore
What it means
SqmJsonTableFunction becomes immutable once its result type is resolved (isTypeResolved() turns true when the AnonymousTupleType for its columns has been computed during query interpretation). checkTypeResolved() guards every structural mutation - adding columns via column()/nested()/ordinalityColumn() - and throws IllegalStateException because the already-computed tuple type would no longer match the definition.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/expression/SqmJsonTableFunction.java:299
return columns.nested( jsonPath );
}
@Override
public JpaJsonTableFunction ordinalityColumn(String columnName) {
columns.ordinalityColumn( columnName );
return this;
}
private void addColumn(String columnName) {
checkTypeResolved();
if ( !columnNames.add( columnName ) ) {
throw new IllegalStateException( "Duplicate column: " + columnName );
}
}
private void checkTypeResolved() {
if ( isTypeResolved() ) {
throw new IllegalStateException(
"Type for json_table function is already resolved. Mutation is not allowed anymore" );
}
}
@Override
public boolean equals(@Nullable Object object) {
return object instanceof SqmJsonTableFunction<?> that
&& super.equals( object )
&& columns.equals( that.columns )
&& Objects.equals( passingExpressions, that.passingExpressions )
&& errorBehavior == that.errorBehavior;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + columns.hashCode();
result = 31 * result + Objects.hashCode( passingExpressions );View on GitHub (pinned to fad1729dce)
Solutions
- Finish all columns()/passing()/error-behavior calls before handing the function to createQuery() or executing the query.
- Copy the node and mutate the copy - table.copy(SqmCopyContext.simpleContext()) - then add columns to the copy.
- Build a fresh json_table function per query instead of reusing an instance.
Example fix
// before - mutate a function already used in a query t.column( "extra", "$.extra", String.class ); // IllegalStateException: type already resolved // after - copy first, then mutate the copy SqmJsonTableFunction<?> t2 = t.copy( SqmCopyContext.simpleContext() ); t2.column( "extra", "$.extra", String.class );
Defensive patterns
Strategy: validation
Validate before calling
private boolean jsonTableUsedInQuery = false;
void afterCreateQuery() {
jsonTableUsedInQuery = true; // type resolution has happened past this point
}
void mutate(JpaJsonTableFunction<?> t) {
if ( jsonTableUsedInQuery ) {
throw new IllegalStateException( "json_table already used - build a new node" );
}
} Prevention
- Treat SQM nodes as immutable once a query has been built from them.
- Complete all column/passing/error-behavior definitions before createQuery().
- Copy (SqmCopyContext) or rebuild json_table nodes when a variant is needed.
When it happens
Trigger: Calling any column-definition method on a json_table node after it was interpreted: reusing one SqmJsonTableFunction across several queries and adding columns for the second one, or mutating a function that a previous createQuery() already processed.
Common situations: Caching SQM fragments or builder objects; shared function instances in request handlers; background mutation of a query tree while another thread renders it; builder-pattern reuse across requests.
Related errors
- immutable global instance of LockOptions
- Unable to locate JdbcValueDescriptor for column `%s`
- Can't emulate null on error clause on DB2
- H2 json_table() only supports literal json paths, but got "
- Can't emulate null on error clause on H2
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/657433f3fba624dd.
Report an issue: GitHub.