{"record":{"id":"2d1d7f46a5835dea","repo":"hibernate/hibernate-orm","slug":"jakarta-persistence-validation-group-is-of-unkn","errorCode":null,"errorMessage":"jakarta.persistence.validation.group.{} is of unknown type: String or Class<?>[] only","messagePattern":"jakarta\\.persistence\\.validation\\.group\\.(.+?) is of unknown type: String or Class<\\?>\\[\\] only","errorType":"exception","errorClass":"HibernateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/GroupsPerOperation.java","lineNumber":97,"sourceCode":"\t\t\t}\n\n\t\t\tfinal List<Class<?>> groupsList = new ArrayList<>( groupNames.length );\n\t\t\tfor ( String groupName : groupNames ) {\n\t\t\t\tfinal String cleanedGroupName = groupName.trim();\n\t\t\t\tif ( !cleanedGroupName.isEmpty() ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tgroupsList.add( classLoaderAccess.classForName( cleanedGroupName ) );\n\t\t\t\t\t}\n\t\t\t\t\tcatch ( ClassLoadingException e ) {\n\t\t\t\t\t\tthrow new HibernateException( \"Unable to load class \" + cleanedGroupName, e );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn groupsList.toArray( new Class<?>[0] );\n\t\t}\n\n\t\t//null is bad and excluded by instanceof => exception is raised\n\t\tthrow new HibernateException( JAKARTA_JPA_GROUP_PREFIX\n\t\t\t\t+ operation.getJakartaGroupPropertyName()\n\t\t\t\t+ \" is of unknown type: String or Class<?>[] only\");\n\t}\n\n\tpublic Class<?>[] get(Operation operation) {\n\t\treturn groupsPerOperation.get( operation );\n\t}\n\n\tpublic enum Operation {\n\t\tPERSIST( \"persist\", JPA_GROUP_PREFIX + \"pre-persist\", JAKARTA_JPA_GROUP_PREFIX + \"pre-persist\" ),\n\t\tMERGE( \"merge\", JAKARTA_JPA_GROUP_PREFIX + \"pre-merge\", JAKARTA_JPA_GROUP_PREFIX + \"pre-merge\" ),\n\t\tREMOVE( \"remove\", JPA_GROUP_PREFIX + \"pre-remove\", JAKARTA_JPA_GROUP_PREFIX + \"pre-remove\" ),\n\t\tINSERT( \"insert\", JAKARTA_JPA_GROUP_PREFIX + \"pre-insert\", JAKARTA_JPA_GROUP_PREFIX + \"pre-insert\", true ),\n\t\tUPDATE( \"update\", JPA_GROUP_PREFIX + \"pre-update\", JAKARTA_JPA_GROUP_PREFIX + \"pre-update\", true ),\n\t\tUPSERT( \"upsert\", JAKARTA_JPA_GROUP_PREFIX + \"pre-upsert\", JAKARTA_JPA_GROUP_PREFIX + \"pre-upsert\", true ),\n\t\tDELETE( \"delete\", JAKARTA_JPA_GROUP_PREFIX + \"pre-delete\", JAKARTA_JPA_GROUP_PREFIX + \"pre-delete\" ),\n\t\tDDL( \"ddl\", HIBERNATE_GROUP_PREFIX + \"ddl\", HIBERNATE_GROUP_PREFIX + \"ddl\", true );\n","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/beanvalidation/GroupsPerOperation.java#L79-L115","documentation":"The value of a jakarta.persistence.validation.group.* property must be either a String (comma-separated class names) or a Class<?>[] / single Class when configuring programmatically. Anything else — List, Set, Properties, Optional — falls through the type checks and hits the final branch, throwing this HibernateException naming the exact property key.","triggerScenarios":"Building a SessionFactory with Map-based settings where a validation group property is bound to a java.util.List (typical when Spring Boot maps a YAML list into jpaProperties) or any non-String, non-Class collection value.","commonSituations":"Spring Boot application.yml lists bound to map values; configuration DSLs that store collections by default; copying list-style config from other frameworks.","solutions":["Pass a single comma-separated String value for the group property","When configuring programmatically, pass Class<?>[] or a Class instance instead of names","For Spring Boot YAML, use a scalar string value, not a YAML list"],"exampleFix":"// before\nMap<String,Object> settings = new HashMap<>();\nsettings.put(\"jakarta.persistence.validation.group.pre-persist\",\n            List.of(\"com.a.G1\", \"com.b.G2\")); // List -> rejected at boot\n\n// after\nsettings.put(\"jakarta.persistence.validation.group.pre-persist\", \"com.a.G1,com.b.G2\");","handlingStrategy":"type-guard","validationCode":"// normalize the value before it reaches Hibernate\nstatic Object sanitizeGroupValue(Object value) {\n    if (value instanceof String || value instanceof Class<?>[] || value instanceof Class<?>) return value;\n    if (value instanceof Collection<?> c)\n        return c.stream().map(String::valueOf).collect(java.util.stream.Collectors.joining(\",\"));\n    throw new IllegalArgumentException(\n        \"validation group value must be a comma-separated String or Class<?>[] but was \"\n        + (value == null ? \"null\" : value.getClass().getName()));\n}","typeGuard":"static boolean isValidGroupSetting(Object value) {\n    return value instanceof String || value instanceof Class<?>[] || value instanceof Class<?>;\n}","tryCatchPattern":"try {\n    sessionFactory = configuration.buildSessionFactory();\n} catch (HibernateException e) {\n    if (e.getMessage().contains(\"is of unknown type: String or Class<?>[] only\"))\n        throw new IllegalStateException(\"Validation group property must be a String or Class<?>[]\", e);\n    throw e;\n}","preventionTips":["Always configure group properties as scalar strings in YAML/properties files","Validate the settings map shape in a startup check before SessionFactory construction"],"tags":["hibernate","bean-validation","validation-groups","configuration","type-mismatch"],"backgroundTag":"invalid-configuration-value","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}