{"record":{"id":"0d357e3c404aadf4","repo":"hibernate/hibernate-orm","slug":"invalid-path-provided-to-fk-function","errorCode":null,"errorMessage":"Invalid path provided to 'fk()' function: {}","messagePattern":"Invalid path provided to 'fk\\(\\)' function: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmFkExpression.java","lineNumber":53,"sourceCode":"\t\t\tNavigablePath navigablePath,\n\t\t\tSqmPath<?> toOnePath) {\n\t\tsuper(\n\t\t\t\tnavigablePath,\n\t\t\t\t(SqmPathSource<T>)\n\t\t\t\t\t\tcastNonNull( pathDomainType( toOnePath )\n\t\t\t\t\t\t\t\t.getIdentifierDescriptor() ),\n\t\t\t\ttoOnePath,\n\t\t\t\ttoOnePath.nodeBuilder()\n\t\t);\n\t}\n\n\tprivate static IdentifiableDomainType<?> pathDomainType(SqmPath<?> toOnePath) {\n\t\tif ( toOnePath.getReferencedPathSource().getPathType()\n\t\t\t\tinstanceof IdentifiableDomainType<?> identifiableDomainType ) {\n\t\t\treturn identifiableDomainType;\n\t\t}\n\t\telse {\n\t\t\tthrow new IllegalArgumentException( \"Invalid path provided to 'fk()' function: \"\n\t\t\t\t\t\t\t\t\t\t\t\t+ toOnePath.getNavigablePath() );\n\t\t}\n\t}\n\n\t@Override\n\tpublic @Nonnull SqmPath<?> getLhs() {\n\t\treturn castNonNull( super.getLhs() );\n\t}\n\n\t@Override\n\tpublic <X> X accept(SemanticQueryWalker<X> walker) {\n\t\treturn walker.visitFkExpression( this );\n\t}\n\n\t@Override\n\tpublic void appendHqlString(StringBuilder hql, SqmRenderContext context) {\n\t\thql.append( \"fk(\" );\n\t\tgetLhs().appendHqlString( hql, context );","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmFkExpression.java#L35-L71","documentation":"fk() is an HQL function that exposes the raw foreign-key column value(s) of a to-one association. SqmFkExpression.pathDomainType requires the path's referenced type to be an IdentifiableDomainType (i.e. the path navigates a @ManyToOne/@OneToOne to an entity); anything else (embeddable, basic attribute, or a plural attribute path) throws IllegalArgumentException naming the offending NavigablePath.","triggerScenarios":"HQL such as 'where fk(p.owner) = :id' when p.owner is an @Embedded attribute, a basic column, or a @OneToMany/@ManyToMany collection; building the same construct through the criteria API; calling fk() on a composite/embedded FK instead of the association itself.","commonSituations":"Developers assuming fk() extracts any 'id-like' column; using fk() against embedded composite FKs; porting native-SQL correlated-subquery idioms that compare raw FK columns into HQL; entity graphs where the association was refactored into an embeddable.","solutions":["Apply fk() only to a to-one association attribute: fk(p.department) where 'department' is @ManyToOne or @OneToOne to an entity","For embedded identifiers or embedded values, navigate the association or its parts directly (p.address.zipCode) instead of fk()","If you need the target's identifier, use the association itself (p.department.id) which Hibernate optimizes to the FK column anyway","Double-check the mapping of the attribute you pass to fk(): it must be entity-typed and singular"],"exampleFix":"// before: address is @Embedded in Person\nselect p.id from Person p where fk(p.address) = :zip\n\n// after: department is @ManyToOne Department in Person\nselect p.id from Person p where fk(p.department) = :deptId","handlingStrategy":"validation","validationCode":"// only pass to-one, entity-typed paths to fk()\nSqmPathSource<?> src = toOnePath.getReferencedPathSource();\nif (!(src.getPathType() instanceof IdentifiableDomainType<?>)) {\n    throw new IllegalArgumentException(\n        \"fk() requires a to-one association to an entity, got: \"\n        + toOnePath.getNavigablePath());\n}\n// safe: emf.getCriteriaBuilder()... query using fk(toOnePath)","typeGuard":"static boolean isToOneEntityPath(SqmPath<?> path) {\n    SqmPathSource<?> src = path.getReferencedPathSource();\n    return src.getPathType() instanceof IdentifiableDomainType<?>\n        && !(src.getSqmType() instanceof org.hibernate.metamodel.model.domain.PluralAttribute<?, ?, ?>);\n}","tryCatchPattern":"try {\n    return em.createQuery(\"select fk(p.department) from Person p where ...\", Long.class);\n} catch (IllegalArgumentException e) {\n    // message contains the offending NavigablePath: fix the path to a @ManyToOne/@OneToOne attribute\n    throw new IllegalArgumentException(\"fk() misuse in query: \" + e.getMessage(), e);\n}","preventionTips":["Reserve fk() for @ManyToOne/@OneToOne association paths only","For embedded or basic values, navigate the attribute path directly instead of fk()","Remember p.target.id is automatically optimized to the FK column - usually you do not need fk() at all","When porting native SQL FK comparisons, double-check each fk() argument is an entity association"],"tags":["hibernate","hql","fk-function","foreign-key","sqm"],"backgroundTag":"hql-fk-function-misuse","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}