{"record":{"id":"6b7edc4e296829a5","repo":"hibernate/hibernate-orm","slug":"unable-to-locate-persister","errorCode":null,"errorMessage":"Unable to locate persister: {}","messagePattern":"Unable to locate persister: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappingMetamodelImpl.java","lineNumber":551,"sourceCode":"\t\treturn jpaMetamodel.enumValue( enumType, enumValueName );\n\t}\n\n\t@Override\n\tpublic String getImportedName(String name) {\n\t\tfinal String qualifiedName = jpaMetamodel.qualifyImportableName( name );\n\t\treturn qualifiedName == null ? name : qualifiedName;\n\t}\n\n\t@Override\n\tpublic void forEachCollectionDescriptor(Consumer<CollectionPersister> action) {\n\t\tcollectionPersisterMap.values().forEach( action );\n\t}\n\n\t@Override\n\tpublic CollectionPersister getCollectionDescriptor(String role) {\n\t\tfinal var collectionPersister = collectionPersisterMap.get( role );\n\t\tif ( collectionPersister == null ) {\n\t\t\tthrow new IllegalArgumentException( \"Unable to locate persister: \" + role );\n\t\t}\n\t\treturn collectionPersister;\n\t}\n\n\t@Override\n\tpublic CollectionPersister getCollectionDescriptor(NavigableRole role) {\n\t\tthrow new UnsupportedOperationException();\n\t}\n\n\t@Override\n\tpublic CollectionPersister findCollectionDescriptor(NavigableRole role) {\n\t\tthrow new UnsupportedOperationException();\n\t}\n\n\t@Override\n\tpublic CollectionPersister findCollectionDescriptor(String role) {\n\t\treturn collectionPersisterMap.get( role );\n\t}","sourceCodeStart":533,"sourceCodeEnd":569,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MappingMetamodelImpl.java#L533-L569","documentation":"MappingMetamodelImpl.getCollectionDescriptor(String role) looks up a collection persister by its role ('EntityName.collectionProperty'); a miss throws IllegalArgumentException('Unable to locate persister: ' + role). Roles are exact strings — FQNs of the property path, not of the class.","triggerScenarios":"Runtime APIs that take a collection role (cache configuration, filters, custom loaders, tooling): role 'Customer.orders' where the attribute is 'orderList', a typo, or the collection is mapped in another persistence unit; building the role from the class's fully-qualified name instead of the entity name.","commonSituations":"Second-level cache region configuration strings drift after renaming attributes or entities; code enumerates roles by hand; refactoring renames the collection property but config strings lag behind.","solutions":["Use the exact role: registered entity name + '.' + collection attribute name (e.g. 'Customer.orders'), matching @Entity(name=...) if set","Dump the real roles once and compare: sessionFactory.getRuntimeMetamodelImplementor().forEachCollectionDescriptor(p -> System.out.println(p.getRole()))","Prefer a null-safe check (findCollectionDescriptor(role) == null) with a clear error listing valid roles"],"exampleFix":"// before\nCollectionPersister p = mappingMetamodel.getCollectionDescriptor(\"com.acme.Customer.orders\"); // FQN -> IllegalArgumentException\n\n// after\nCollectionPersister p = mappingMetamodel.getCollectionDescriptor(\"Customer.orders\"); // entity name + property","handlingStrategy":"validation","validationCode":"CollectionPersister findOrThrow(SessionFactory sf, String role) {\n  MappingMetamodel mm = (MappingMetamodel) sf.getMetamodel();\n  CollectionPersister p = mm.findCollectionDescriptor(role); // null-safe sibling\n  if (p == null) {\n    List<String> roles = new ArrayList<>();\n    mm.forEachCollectionDescriptor(cp -> roles.add(cp.getRole()));\n    throw new IllegalArgumentException(\"Unknown collection role '\" + role + \"'; registered: \" + roles);\n  }\n  return p;\n}","typeGuard":null,"tryCatchPattern":"try {\n  return mappingMetamodel.getCollectionDescriptor(role);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Unable to locate persister\")) {\n    // role strings are exact: 'EntityName.collectionProperty'; recheck against registered roles\n    throw new IllegalArgumentException(\"Unknown collection role '\" + role + \"'\", e);\n  }\n  throw e;\n}","preventionTips":["Build role strings as entityName + '.' + propertyName, honoring @Entity(name=...)","Cache and log the registered role list at startup (forEachCollectionDescriptor) to catch drift from renames","Keep cache-region and loader configuration roles in the same change unit as the mapped property"],"tags":["hibernate","collection","role","runtime-lookup"],"backgroundTag":"unknown-collection-role","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}