{"record":{"id":"657433f3fba624dd","repo":"hibernate/hibernate-orm","slug":"type-for-json-table-function-is-already-resolved","errorCode":null,"errorMessage":"Type for json_table function is already resolved. Mutation is not allowed anymore","messagePattern":"Type for json_table function is already resolved\\. Mutation is not allowed anymore","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/expression/SqmJsonTableFunction.java","lineNumber":299,"sourceCode":"\t\treturn columns.nested( jsonPath );\n\t}\n\n\t@Override\n\tpublic JpaJsonTableFunction ordinalityColumn(String columnName) {\n\t\tcolumns.ordinalityColumn( columnName );\n\t\treturn this;\n\t}\n\n\tprivate void addColumn(String columnName) {\n\t\tcheckTypeResolved();\n\t\tif ( !columnNames.add( columnName ) ) {\n\t\t\tthrow new IllegalStateException( \"Duplicate column: \" + columnName );\n\t\t}\n\t}\n\n\tprivate void checkTypeResolved() {\n\t\tif ( isTypeResolved() ) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Type for json_table function is already resolved. Mutation is not allowed anymore\" );\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object object) {\n\t\treturn object instanceof SqmJsonTableFunction<?> that\n\t\t\t&& super.equals( object )\n\t\t\t&& columns.equals( that.columns )\n\t\t\t&& Objects.equals( passingExpressions, that.passingExpressions )\n\t\t\t&& errorBehavior == that.errorBehavior;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tint result = super.hashCode();\n\t\tresult = 31 * result + columns.hashCode();\n\t\tresult = 31 * result + Objects.hashCode( passingExpressions );","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/expression/SqmJsonTableFunction.java#L281-L317","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before - mutate a function already used in a query\nt.column( \"extra\", \"$.extra\", String.class ); // IllegalStateException: type already resolved\n\n// after - copy first, then mutate the copy\nSqmJsonTableFunction<?> t2 = t.copy( SqmCopyContext.simpleContext() );\nt2.column( \"extra\", \"$.extra\", String.class );","handlingStrategy":"validation","validationCode":"private boolean jsonTableUsedInQuery = false;\n\nvoid afterCreateQuery() {\n    jsonTableUsedInQuery = true; // type resolution has happened past this point\n}\n\nvoid mutate(JpaJsonTableFunction<?> t) {\n    if ( jsonTableUsedInQuery ) {\n        throw new IllegalStateException( \"json_table already used - build a new node\" );\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["hibernate","json-table","sqm","immutability","mutation"],"backgroundTag":"immutable-state-mutation","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}