{"record":{"id":"062d9d147fc948de","repo":"hibernate/hibernate-orm","slug":"can-t-use-expression-expression-without-e","errorCode":null,"errorMessage":"Can't use expression '\" + expression + \" without explicit name in xmlforest function, because XML element names can only be derived from path expressions.","messagePattern":"Can't use expression '\" \\+ expression \\+ \" without explicit name in xmlforest function, because XML element names can only be derived from path expressions\\.","errorType":"exception","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java","lineNumber":6578,"sourceCode":"\tpublic <T> SqmExpression<T> named(Expression<T> expression, String name) {\n\t\treturn new SqmNamedExpression<>( (SqmExpression<T>) expression, name );\n\t}\n\n\t@Override\n\tpublic SqmExpression<String> xmlforest(Expression<?>... elements) {\n\t\treturn xmlforest( asList( elements ) );\n\t}\n\n\t@Override\n\tpublic SqmExpression<String> xmlforest(List<? extends Expression<?>> elements) {\n\t\tfinal ArrayList<SqmExpression<?>> arguments = new ArrayList<>( elements.size() );\n\t\tfor ( Expression<?> expression : elements ) {\n\t\t\tif ( expression instanceof SqmNamedExpression<?> ) {\n\t\t\t\targuments.add( (SqmNamedExpression<?>) expression );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ( !( expression instanceof SqmPath<?> path ) || !( path.getModel() instanceof PersistentAttribute<?, ?> attribute ) ) {\n\t\t\t\t\tthrow new SemanticException(\n\t\t\t\t\t\t\t\"Can't use expression '\" + expression + \" without explicit name in xmlforest function\"+\n\t\t\t\t\t\t\t\t\t\", because XML element names can only be derived from path expressions.\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\targuments.add( new SqmNamedExpression<>( (SqmExpression<?>) expression, attribute.getName() ) );\n\t\t\t}\n\t\t}\n\t\treturn getFunctionDescriptor( \"xmlforest\" ).generateSqmExpression(\n\t\t\t\targuments,\n\t\t\t\tnull,\n\t\t\t\tqueryEngine\n\t\t);\n\t}\n\n\t@Override\n\tpublic SqmExpression<String> xmlconcat(Expression<?>... elements) {\n\t\treturn xmlconcat( asList( elements ) );\n\t}","sourceCodeStart":6560,"sourceCodeEnd":6596,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java#L6560-L6596","documentation":"The xmlforest(criteria) function builds XML fragments where every element needs a name. A name can only be derived automatically from a path over a persistent attribute (SqmPath whose model is a PersistentAttribute); any other expression (literal, aggregate, arithmetic, subquery, parameter) must carry an explicit name by being an SqmNamedExpression. Otherwise Hibernate throws SemanticException because it cannot invent a valid XML element name.","triggerScenarios":"cb.xmlforest(root.get(\"name\"), cb.count(rootJoin.get(\"id\"))) — the count() has no attribute name; passing literals (cb.literal(42)), coalesce/case expressions, or alias-less function results; calling xmlforest(Expression...) with values produced by helper builders that never call alias().","commonSituations":"Porting SQL 'xmlforest(...)' projections that mix columns and computed values; report builders generating XML output where aggregates like sum()/count() are added without labels; XML export features on PostgreSQL.","solutions":["Attach an explicit name to computed elements using the alias support so they become named expressions: cb.xmlforest(root.get(\"name\"), cb.count(...).alias(\"order_count\")) or your builder's named wrapper (SqmNamedExpression via alias()).","Restrict automatically named elements to direct attribute paths (root.get(\"attr\")).","If alias() alone doesn't register as a named expression in your version, project through cb.concat/xmlforest with explicit xmlserialize/xmlconcat names or use HQL 'xmlforest(name as x, ...)' with aliases."],"exampleFix":"// before\nExpression<Long> cnt = cb.count(orderRoot.get(\"id\"));\ncb.xmlforest(customer.get(\"name\"), cnt); // cnt is not a path -> SemanticException\n\n// after\nExpression<Long> cnt = cb.count(orderRoot.get(\"id\")).alias(\"orderCount\"); // explicit name\ncb.xmlforest(customer.get(\"name\"), cnt);","handlingStrategy":"validation","validationCode":"boolean canAutoName(Expression<?> e) {\n    return e instanceof Path<?> p && p.getModel() instanceof Attribute<?, ?>;\n}\n// every non-path element must be named:\nif (!canAutoName(e) && e.getAlias() == null) throw new IllegalArgumentException(\"element needs explicit alias/name\");","typeGuard":"static boolean xmlforestSafe(Expression<?> e) {\n    return (e instanceof Path<?> p && p.getModel() instanceof Attribute<?, ?>)\n            || e.getAlias() != null; // aliased expressions carry a name\n}","tryCatchPattern":"try {\n    x = cb.xmlforest(elements);\n} catch (SemanticException e) {\n    if (e.getMessage().contains(\"xmlforest\")) { /* alias each computed element and rebuild */ }\n    else throw e;\n}","preventionTips":["Alias every computed element (count, sum, coalesce, literal) before passing it to xmlforest.","Reserve unaliased elements for direct attribute paths.","Add a builder-level check that all xmlforest arguments are paths or aliased."],"tags":["hibernate","criteria","xmlforest","xml","semantic"],"backgroundTag":"xmlforest-unnamed-expression","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}