{"record":{"id":"837edea778cc97b1","repo":"hibernate/hibernate-orm","slug":"non-aggregate-composite-paths-cannot-be-treat-ed","errorCode":null,"errorMessage":"Non-aggregate composite paths cannot be TREAT-ed","messagePattern":"Non-aggregate composite paths cannot be TREAT-ed","errorType":"exception","errorClass":"TreatException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/NonAggregatedCompositeSimplePath.java","lineNumber":63,"sourceCode":"\t\t\t\t\t\tgetNavigablePathCopy( lhsCopy ),\n\t\t\t\t\t\tgetModel(),\n\t\t\t\t\t\tlhsCopy,\n\t\t\t\t\t\tnodeBuilder()\n\t\t\t\t)\n\t\t);\n\t\tcopyTo( path, context );\n\t\treturn path;\n\t}\n\n\t@Override\n\tpublic <X> X accept(SemanticQueryWalker<X> walker) {\n\t\treturn walker.visitNonAggregatedCompositeValuedPath( this );\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic <S extends T> SqmTreatedEntityValuedSimplePath<T, S> treatAs(@Nonnull Class<S> treatJavaType) {\n\t\tthrow new TreatException( \"Non-aggregate composite paths cannot be TREAT-ed\" );\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic <S extends T> SqmTreatedSimplePath<T, S> treatAs(@Nonnull EntityDomainType<S> treatTarget) {\n\t\tthrow new TreatException( \"Non-aggregate composite paths cannot be TREAT-ed\" );\n\t}\n\n\t@Override\n\t@Nonnull\n\tpublic <S extends T> SqmTreatedSimplePath<T, S> treatAs(@Nonnull Class<S> treatJavaType, @Nullable String alias) {\n\t\tthrow new TreatException( \"Non-aggregate composite paths cannot be TREAT-ed\" );\n\t}\n\n\t@Override\n\t@Nonnull\n\tpublic <S extends T> SqmTreatedSimplePath<T, S> treatAs(@Nonnull EntityDomainType<S> treatTarget, @Nullable String alias) {\n\t\tthrow new TreatException( \"Non-aggregate composite paths cannot be TREAT-ed\" );","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/NonAggregatedCompositeSimplePath.java#L45-L81","documentation":"NonAggregatedCompositeSimplePath represents the SQM path over the identity of an entity that uses a non-aggregated composite id — @IdClass style, or @Id placed directly on fields of an embedded shared with the entity rather than a standalone @EmbeddedId aggregate. The one-argument overload treatAs(Class) (declared to return SqmTreatedEntityValuedSimplePath) throws TreatException('Non-aggregate composite paths cannot be TREAT-ed') because the composite id has no type hierarchy of its own to downcast to: its runtime type is fixed by the mapping, so the TREAT is meaningless. It fires while the SQM tree is built (HQL parsing or criteria building), before any SQL is produced.","triggerScenarios":"HQL 'from Order o where treat(o.id as SubIdClass).branchCode = :b' where Order's id is a non-aggregated composite (@IdClass or @Id-on-embeddable fields). Criteria equivalent: root.get(\"id\").treat(SubIdClass.class) or ((JpaPath<?>) root.get(\"id\")).treatAs(SubIdClass.class). Also reached when TREAT wraps a path derived from such an id after a join, e.g. treat(other.orderId as SubId).","commonSituations":"Legacy schemas with composite keys (@IdClass, @Id on embeddable fields); queries ported from single-column-key entities where TREAT on the root worked fine; template-generated criteria code that adds treat() to every path; inheritance hierarchies sharing a composite key where someone tries to reach subtype columns through the id.","solutions":["Drop the TREAT and navigate the component fields directly: o.id.branchCode in HQL, or root.get(\"id\").get(\"branchCode\") in criteria.","If the intent was to downcast the entity, apply TREAT to the entity alias instead — treat(o as SubOrder) — then navigate its id fields.","Compare the individual key columns in the predicate instead of downcasting the id.","If subtype-specific id fields are genuinely required, switch to an @EmbeddedId (aggregated) mapping or add a real association — non-aggregated composite ids cannot model polymorphism."],"exampleFix":"// before - Order uses a non-aggregated composite id\n// HQL: from Order o where treat(o.id as BranchOrderPK).branchCode = 'X'\n// -> TreatException: Non-aggregate composite paths cannot be TREAT-ed\n\n// after - navigate the component fields, no downcast needed\n// HQL: from Order o where o.id.branchCode = 'X'\nquery.where(cb.equal(root.get(\"id\").get(\"branchCode\"), \"X\"));","handlingStrategy":"type-guard","validationCode":"// composite (id-class) ids are never treatable: detect before building the query\njakarta.persistence.metamodel.EntityType<Order> order = root.getModel();\nif (!order.hasSingleIdAttribute()) {\n    // @IdClass / non-aggregated composite id: forbid any treat on the id path\n    throw new IllegalArgumentException(\"Order has a non-aggregated composite id; navigate o.id fields directly\");\n}","typeGuard":"static boolean hasNonAggregatedCompositeId(EntityType<?> entityType) {\n    return !entityType.hasSingleIdAttribute(); // false => @IdClass-style composite id\n}","tryCatchPattern":"try {\n    path.treatAs(SubType.class);\n} catch (org.hibernate.query.sqm.TreatException e) {\n    // message: 'Non-aggregate composite paths cannot be TREAT-ed'\n    throw new QueryBuildException(\"TREAT not applicable to composite id path: \" + e.getMessage(), e);\n}","preventionTips":["Remember TREAT only applies to entity references in an inheritance hierarchy; ids and embeddables are never treatable.","For @IdClass entities, navigate the id fields directly (o.id.branchCode).","Flag 'treat(' near '.id' in HQL during code review.","When a downcast was intended, put TREAT on the entity alias, not its identifier."],"tags":["hibernate","sqm","treat","composite-key","idclass","embedded-id","hql"],"backgroundTag":"treat-on-composite-id","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}