{"record":{"id":"cc13aa2c6b890057","repo":"hibernate/hibernate-orm","slug":"fk-paths-cannot-be-treat-ed","errorCode":null,"errorMessage":"Fk paths cannot be TREAT-ed","messagePattern":"Fk 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/SqmFkExpression.java","lineNumber":91,"sourceCode":"\t}\n\n\t@Override\n\tpublic SqmFkExpression<T> copy(SqmCopyContext context) {\n\t\tfinal var existing = context.getCopy( this );\n\t\tif ( existing != null ) {\n\t\t\treturn existing;\n\t\t}\n\t\tfinal var lhsCopy = (SqmEntityValuedSimplePath<?>) getLhs().copy( context );\n\t\treturn context.registerCopy(\n\t\t\t\tthis,\n\t\t\t\tnew SqmFkExpression<>( getNavigablePathCopy( lhsCopy ), lhsCopy )\n\t\t);\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic <S extends T> SqmTreatedPath<T,S> treatAs(@Nonnull Class<S> treatJavaType) {\n\t\tthrow new TreatException( \"Fk paths cannot be TREAT-ed\" );\n\t}\n\n\t@Nonnull\n\t@Override\n\tpublic <S extends T> SqmTreatedPath<T,S> treatAs(@Nonnull EntityDomainType<S> treatTarget) {\n\t\tthrow new TreatException( \"Fk paths cannot be TREAT-ed\" );\n\t}\n\n\t@Override\n\tpublic SqmPath<?> resolvePathPart(String name, boolean isTerminal, SqmCreationState creationState) {\n\t\tfinal var sqmPath = get( name, true );\n\t\tcreationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );\n\t\treturn sqmPath;\n\t}\n}\n","sourceCodeStart":73,"sourceCodeEnd":107,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmFkExpression.java#L73-L107","documentation":"The result of fk() is a synthetic expression over the FK column(s), not a domain path with type identity, so SqmFkExpression.treatAs(Class) unconditionally throws TreatException. TREAT must be applied to the underlying entity association, not to the extracted key value.","triggerScenarios":"HQL 'treat(fk(p.pet) as Dog)' or criteria code calling fkExpression.treatAs(Dog.class) on the result of the fk() function.","commonSituations":"Trying to combine Hibernate's fk() optimization with entity downcasting in one expression; criteria wrappers that automatically treat paths supplied by users; copy-pasting a TREAT pattern onto an fk() expression.","solutions":["Apply TREAT to the association path first, then extract the FK if needed: fk(treat(p.pet as Dog)) or simply join treat(p.pet as Dog) d","Rewrite the query to join and treat the association, putting conditions on the joined alias","If you only need the FK value, call fk() on the untreated association: fk(p.pet)"],"exampleFix":"// before\nfrom Person p join treat(fk(p.pet) as Dog) d\n\n// after\nfrom Person p join treat(p.pet as Dog) d\n// if you need the raw FK value: select fk(treat(p.pet as Dog)) from Person p","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"static boolean supportsTreat(SqmExpression<?> expr) {\n    return !(expr instanceof SqmFkExpression<?>);\n}","tryCatchPattern":"try {\n    treated = expr.treatAs(target);\n} catch (TreatException e) {\n    // expr was an fk() result: re-apply treat on the underlying association instead\n    throw new IllegalStateException(\"TREAT the to-one association before fk(), not after\", e);\n}","preventionTips":["Never apply TREAT to the result of fk(); treat the association first","Keep fk() as the outermost operation in an expression","In shared query helpers, instanceof-check SqmFkExpression before treatAs"],"tags":["hibernate","hql","treat","fk-function","sqm"],"backgroundTag":"invalid-treat-target","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}