{"record":{"id":"07d5183cbb4ddbd7","repo":"hibernate/hibernate-orm","slug":"couldn-t-determine-basic-type-for-java-type","errorCode":null,"errorMessage":"Couldn't determine basic type for java type: {}","messagePattern":"Couldn't determine basic type for java type: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmFunctionPath.java","lineNumber":64,"sourceCode":"\t\tthis.function = function;\n\t}\n\n\tprivate static <X> SqmPathSource<X> determinePathSource(NavigablePath navigablePath, SqmFunction<?> function) {\n\t\t//noinspection unchecked\n\t\tfinal var nodeType = (SqmBindableType<X>) function.getNodeType();\n\t\tif ( nodeType == null ) {\n\t\t\tthrow new IllegalArgumentException( \"Null return type for function: \" + function.getFunctionName() );\n\t\t}\n\t\tfinal var bindableJavaType = nodeType.getJavaType();\n\t\tfinal var managedType =\n\t\t\t\tfunction.nodeBuilder().getJpaMetamodel()\n\t\t\t\t\t\t.findManagedType( bindableJavaType );\n\t\tif ( managedType == null ) {\n\t\t\tfinal var basicType =\n\t\t\t\t\tfunction.nodeBuilder().getTypeConfiguration()\n\t\t\t\t\t\t\t.getBasicTypeForJavaType( bindableJavaType );\n\t\t\tif ( basicType == null ) {\n\t\t\t\tthrow new IllegalArgumentException( \"Couldn't determine basic type for java type: \" + bindableJavaType.getName() );\n\t\t\t}\n\t\t\treturn new BasicSqmPathSource<>(\n\t\t\t\t\tnavigablePath.getFullPath(),\n\t\t\t\t\tnull,\n\t\t\t\t\tbasicType,\n\t\t\t\t\tbasicType.getRelationalJavaType(),\n\t\t\t\t\tBindable.BindableType.SINGULAR_ATTRIBUTE,\n\t\t\t\t\tfalse\n\t\t\t);\n\t\t}\n\t\telse if ( managedType.getPersistenceType() == Type.PersistenceType.EMBEDDABLE ) {\n\t\t\treturn new EmbeddedSqmPathSource<>(\n\t\t\t\t\tnavigablePath.getFullPath(),\n\t\t\t\t\tnull,\n\t\t\t\t\t(SqmEmbeddableDomainType<X>) managedType,\n\t\t\t\t\tBindable.BindableType.SINGULAR_ATTRIBUTE,\n\t\t\t\t\tfalse\n\t\t\t);","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmFunctionPath.java#L46-L82","documentation":"While building the path source for a navigable function result, SqmFunctionPath.determinePathSource looks up the function's return Java type in the JpaMetamodel (managed types) and then in the basic-type registry. If neither knows the Java type, no SqmPathSource can be constructed and IllegalArgumentException is thrown naming the class. This means the function returns a Java type for which no basic/mapped type is registered.","triggerScenarios":"A custom function whose descriptor declares an exotic return Java type (custom value class, Object, Serializable, an unregistered record) with no BasicType/JavaTypeDescriptor registered; navigating attributes from such a function result: f(e.x).sub.","commonSituations":"Domain value objects (Money, Coordinate) used as function return types without a @Type/JavaTypeRegistration or BasicTypeContributor; upgrading Hibernate versions where lax type resolution was tightened; functions returning Object in utility libraries.","solutions":["Register a basic type / JavaTypeDescriptor for the return Java type (metadataBuilder.applyBasicType(...), @JavaTypeRegistration, or a TypeContributor) so getBasicTypeForJavaType(rt) resolves","Change the function descriptor to declare a standard mapped return type (String, Integer, etc.)","Wrap the call in cast(f(x) as ...) to force a concrete mapped type before navigating","If the return type is actually a mapped embeddable/entity, make sure it is part of the persistence unit so findManagedType finds it"],"exampleFix":"// before: function returns Money, no type registered\n// HQL: select money_of(p).amount from Person p\n//  -> \"Couldn't determine basic type for java type: com.acme.Money\"\n\n// after: register the type before building the SessionFactory\nStandardServiceRegistryBuilder builder = ...;\nMetadataBuilder mb = new MetadataBuilderImpl(builder.build())...;\nmb.applyBasicType(new MoneyType()); // Money <-> MoneyType mapping\n// or annotate the domain class: @JavaType(MoneyJavaTypeDescriptor.class)","handlingStrategy":"validation","validationCode":"// verify the function's return Java type is known to the factory before navigating\nClass<?> rt = function.getNodeType().getJavaType();\nSessionFactoryImplementor sfi = emf.unwrap(SessionFactoryImplementor.class);\nboolean known = sfi.getJpaMetamodel().findManagedType(rt) != null\n            || sfi.getTypeConfiguration().getBasicTypeForJavaType(rt) != null;\nif (!known) {\n    throw new IllegalStateException(\"No basic/managed type registered for \" + rt.getName()\n        + \"; register it via metadataBuilder.applyBasicType or @JavaTypeRegistration\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    path = new SqmFunctionPath<>(function).get(attr);\n} catch (IllegalArgumentException e) {\n    // message names the unmapped Java type: add a BasicType/JavaTypeDescriptor registration\n    throw new IllegalStateException(\"Unmapped function return type; register a type mapping\", e);\n}","preventionTips":["Register BasicType/JavaTypeDescriptor mappings for custom value classes returned by functions","Prefer standard Java types (String, BigDecimal, ...) as custom function return types","Cover function-return types in mapping tests before using them in HQL navigation","Keep @JavaTypeRegistration/@Type registrations alongside the domain model so types resolve globally"],"tags":["hibernate","type-mapping","custom-function","basic-type","sqm"],"backgroundTag":"missing-type-mapping","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}