{"record":{"id":"69d304eb31b7b6cd","repo":"hibernate/hibernate-orm","slug":"unsupported-attempt-to-set-an-explicit-custom-type","errorCode":null,"errorMessage":"Unsupported attempt to set an explicit-custom-type when value is already resolved","messagePattern":"Unsupported attempt to set an explicit-custom-type when value is already resolved","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java","lineNumber":1088,"sourceCode":"\tpublic void setTypeName(String typeName) {\n\t\tif ( isEmpty( typeName ) ) {\n\t\t\tsuper.setTypeName( typeName );\n\t\t}\n\t\telse if ( typeName.startsWith( TYPE_NAME_PREFIX ) ) {\n\t\t\tsetAttributeConverterDescriptor( typeName );\n\t\t}\n\t\telse {\n\t\t\tsetExplicitTypeName( typeName );\n\t\t\tsuper.setTypeName( typeName );\n\t\t}\n\t}\n\n\tprivate static int COUNTER;\n\n\tpublic void setExplicitCustomType(Class<? extends UserType<?>> explicitCustomType) {\n\t\tif ( explicitCustomType != null ) {\n\t\t\tif ( resolution != null ) {\n\t\t\t\tthrow new UnsupportedOperationException( \"Unsupported attempt to set an explicit-custom-type when value is already resolved\" );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfinal var parameters = buildCustomTypeProperties();\n\t\t\t\tresolution = new UserTypeResolution<>(\n\t\t\t\t\t\tnew CustomType<>(\n\t\t\t\t\t\t\t\tgetConfiguredUserTypeBean( explicitCustomType, getTypeAnnotation(), parameters ),\n\t\t\t\t\t\t\t\tgetTypeConfiguration()\n\t\t\t\t\t\t),\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\tparameters\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate Properties buildCustomTypeProperties() {\n\t\tfinal var properties = new Properties();\n\t\tif ( isNotEmpty( getTypeParameters() ) ) {","sourceCodeStart":1070,"sourceCodeEnd":1106,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/mapping/BasicValue.java#L1070-L1106","documentation":"BasicValue.setExplicitCustomType builds a resolution immediately; once the value already has a resolution (e.g., a type name was set first), setting an explicit custom type is rejected as an unsupported state transition. In practice it means one attribute carries conflicting type specifications.","triggerScenarios":"An attribute annotated with both @Type/@JdbcTypeCode-derived specification and @CustomType, so processing sets the type name first and the custom type second; programmatic mapping calling setTypeName(...) then setExplicitCustomType(...); composed annotations applying type specs twice.","commonSituations":"Introducing @CustomType over legacy @Type mappings during a Hibernate 6.2+ upgrade; meta-annotated stereotypes stacking type annotations; in-house mapping frameworks mutating BasicValue after resolution.","solutions":["Keep exactly one type specification per attribute: @CustomType alone, or @Type/@JdbcTypeCode alone.","Remove the legacy @Type/@TypeDef where @CustomType is introduced.","In programmatic mapping, set the custom type before any type-name resolution happens."],"exampleFix":"// before\n@Type(MyType.class)\n@CustomType(MyUserType.class)\nprivate String phone;\n\n// after\n@CustomType(MyUserType.class)\nprivate String phone;","handlingStrategy":"validation","validationCode":"static boolean hasConflictingType( Field f ) {\n    return f.isAnnotationPresent( Type.class ) && f.isAnnotationPresent( CustomType.class );\n}\n// run over mapped classes as a startup audit","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use exactly one type specification per attribute","Remove legacy @Type/@TypeDef when introducing @CustomType","In programmatic mapping, set custom types before any type-name resolution"],"tags":["hibernate","custom-type","annotation-conflict"],"backgroundTag":"conflicting-type-annotations","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}