hibernate/hibernate-orm · error · IllegalArgumentException
Couldn't determine types of columns of function 'json_table'
Error message
Couldn't determine types of columns of function 'json_table'
What it means
Hibernate derives json_table's result type as an AnonymousTupleType built from the declared columns (Columns.createTupleType()). If no columns were defined at all (table.columnNames is empty), there is no type to build and it throws IllegalArgumentException('Couldn't determine types of columns of function json_table'). Most dialects require an explicit COLUMNS clause for JSON_TABLE anyway.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/expression/SqmJsonTableFunction.java:1160
int result = jsonPath.hashCode();
result = 31 * result + SqmCacheable.cacheHashCode( columnDefinitions );
return result;
}
}
public static final class Columns extends NestedColumns implements SqmTypedNode<Object> {
public Columns(SqmJsonTableFunction<?> table) {
super( "", table );
}
private Columns(SqmJsonTableFunction<?> table, ArrayList<ColumnDefinition> columnDefinitions) {
super( "", table, columnDefinitions );
}
public AnonymousTupleType<?> createTupleType() {
if ( table.columnNames.isEmpty() ) {
throw new IllegalArgumentException( "Couldn't determine types of columns of function 'json_table'" );
}
final SqmBindableType<?>[] componentTypes = new SqmBindableType<?>[table.columnNames.size()];
final String[] componentNames = new String[table.columnNames.size()];
int result = populateTupleType( 0, componentNames, componentTypes );
// Sanity check
assert result == componentTypes.length;
return new AnonymousTupleType<>( componentTypes, componentNames );
}
@Override
public Columns copy(SqmCopyContext context) {
final ArrayList<ColumnDefinition> definitions = new ArrayList<>( columnDefinitions.size() );
for ( ColumnDefinition columnDefinition : columnDefinitions ) {
definitions.add( columnDefinition.copy( context ) );
}
return new Columns( castNonNull( context.getCopy( table ) ), definitions );View on GitHub (pinned to fad1729dce)
Solutions
- Always declare at least one column (path column or ordinality column) before executing the query.
- If you only need to test existence, use json_exists instead of json_table.
- Guard dynamic builders: assert that at least one column was added before createQuery().
Example fix
// before JpaJsonTableFunction<?> t = cb.jsonTable( doc, "$" ); // no columns defined // after - declare at least one column cb.jsonTable( doc, "$" ).ordinalityColumn( "n" ); // or a full .columns(...) definition
Defensive patterns
Strategy: validation
Validate before calling
int definedColumns = 0; // increment in every column()/ordinalityColumn() call
if ( definedColumns == 0 ) {
throw new IllegalStateException( "json_table requires at least one column definition" );
}
return em.createQuery( cq ); Prevention
- Always pair json_table with at least one column definition before createQuery().
- Use json_exists for pure existence checks instead of a columnless json_table.
- Add a builder assertion that counts defined columns.
When it happens
Trigger: Creating a json_table criteria node without any columns clause and letting interpretation proceed: cb.jsonTable(doc, path) with no columns()/ordinalityColumn() call, so the lazily computed tuple type finds zero columns.
Common situations: Builder code that conditionally skips the columns clause; refactors that removed the columns call; assuming a columnless JSON_TABLE behaves like json_exists; adapting SQL examples that omit COLUMNS.
Related errors
- Can't pass parameter '{}', because json_table has no JSON pa
- Duplicate column: {}
- Expecting just a single formula/column in context of <%s nam
- Expecting single column in context of <%s name="%s"/>, but f
- column attribute may not be specified along with <column/> o
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/f216b299ddb5a7e1.
Report an issue: GitHub.