Skip to content

MappingAuditableBeanWrapperFactory fails with Couldn't find PersistentEntity #3515

Description

@cchevallier-sys

Auditing fails at startup — "Couldn't find PersistentEntity for type ?" — for entities with nested generic collections (Spring Data 2026.0 / commons 4.1)

Affected versions

  • Spring Boot 4.1.0
  • Spring Data BOM 2026.0.0 → spring-data-commons 4.1.0, spring-data-mongodb 4.1.0, spring-data-rest 5.1.0
  • Reproduces on Java 21 and 25.
  • Works with Spring Data BOM 2025.1.6 (commons 4.0.6), keeping Boot 4.1.0.

Summary

When an audited/REST-exposed MongoDB entity has a nested generic collection property
(e.g. Map<String, Map<String, X>>), building the auditing metadata at startup fails with
MappingException: Couldn't find PersistentEntity for type ?. The auditing bean walks the
property paths of every persistent entity, a raw java.util.Map/List gets registered as
a persistent entity, and resolving its wildcard element type throws.

Minimal reproducer

spring441-auditing-repro.zip
Full project attached; the entire model is four files:

@Document("item")
class Item {
    @Id String id;
    Map<String, Map<String, Cell>> values;   // nested generic map — the trigger
}

class Cell {
    Object value;
}

@RepositoryRestResource
interface ItemRepository extends MongoRepository<Item, String> {}

@SpringBootApplication
@EnableMongoRepositories
@EnableMongoAuditing
class ReproApplication { public static void main(String[] a){ SpringApplication.run(ReproApplication.class,a);} }

pom.xml: spring-boot-starter-parent 4.1.0, deps spring-boot-starter-data-mongodb +
spring-boot-starter-data-rest. ./mvnw spring-boot:run crashes; pinning
<spring-data-bom.version>2025.1.6</spring-data-bom.version> fixes it.

No auditing annotation on Item is required — the metadata builder walks every entity.
Without Spring Data REST it manifests identically via @EnableMongoAuditing's
IsNewAwareAuditingHandler when some entity carries auditing annotations.

Stack trace

BeanCreationException: 'auditableBeanWrapperFactory' … Failed to instantiate
[org.springframework.data.auditing.AuditableBeanWrapperFactory]:
Factory method 'auditableBeanWrapperFactory' threw exception: Couldn't find PersistentEntity for type ?

Caused by: org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type ?
    at o.s.d.mapping.context.MappingContext.getRequiredPersistentEntity(MappingContext.java:121)
    at o.s.d.mapping.context.PersistentPropertyPathFactory.from(PersistentPropertyPathFactory.java:231)
    at o.s.d.mapping.context.PersistentPropertyPathFactory.from(PersistentPropertyPathFactory.java:168)
    at o.s.d.mapping.context.AbstractMappingContext.doFindPersistentPropertyPaths(AbstractMappingContext.java:376)
    at o.s.d.mapping.context.AbstractMappingContext.findPersistentPropertyPaths(AbstractMappingContext.java:360)
    at o.s.d.auditing.MappingAuditableBeanWrapperFactory$MappingAuditingMetadata.findPropertyPaths(…:162)
    at o.s.d.auditing.MappingAuditableBeanWrapperFactory$MappingAuditingMetadata.<init>(…:136)
    at o.s.d.auditing.MappingAuditableBeanWrapperFactory.<init>(…:76)              // iterates every entity
    at o.s.d.rest.webmvc.config.RepositoryRestMvcConfiguration.auditableBeanWrapperFactory(…:863)

Root cause

Diffing the -sources.jar of commons 4.0.6 vs 4.1.0, the one behaviourally relevant
change in the mapping layer is that
AbstractMappingContext$PersistentPropertyCreator.createAndRegisterProperty(...) dropped the
early transient guard
:

P property = createPersistentProperty(input, entity, simpleTypeHolder);
if (property.isTransient()) {      // <-- present in 4.0.6, REMOVED in 4.1.0
    return;
}
...
entity.addPersistentProperty(property);

together with the new transient-property tracking added to BasicPersistentEntity
(transientProperties, transientPropertyCache, getTransientProperty, isTransient(String))
— i.e. the @Transient-in-constructors feature (#2942) from the 2026.0 mapping-layer rewrite.

The side effect: a raw java.util.Map/List now ends up registered as a persistent entity,
and MappingAuditableBeanWrapperFactory (invoked from both
IsNewAwareAuditingHandler.from(...) and Spring Data REST's auditableBeanWrapperFactory)
walks it — TypeInformation.of(Map.class).getActualType() is the wildcard ?, so
getRequiredPersistentEntity(?) throws.

This is functionally the same failure as the long-fixed #3056 (fixed in 3.2.4), reintroduced by
the 4.1 rewrite.

Workaround

Pin Spring Data back one train while keeping Boot 4.1.0:

<properties>
    <spring-data-bom.version>2025.1.6</spring-data-bom.version>
</properties>

Metadata

Metadata

Assignees

Labels

type: regressionA regression from a previous release

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions