Skip to content

MappingAuditableBeanWrapperFactory fails with Couldn't find PersistentEntity #3515

Open

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>

Activity

  1. changed the title [-]Auditing fails at startup — "Couldn't find PersistentEntity for type ?" — for entities with nested generic collections (Spring Data 2026.0 / commons 4.1)[/-] [+]`MappingAuditableBeanWrapperFactory` fails with `Couldn't find PersistentEntity`[/+] on Jul 28, 2026
  2. self-assigned this
    on Jul 28, 2026
  3. mp911de commented on Jul 28, 2026

    @mp911de
    Member

    Thank you for your issue report. We appreciate community contributions, but we do need them to meet a reasonable baseline for consideration.

    Tip

    This means:

    • Expressing your intent with a concise and reasonable description

    When issues require significant effort from our side to initially understand your request, we have to deprioritize or even reject them in favor of tickets that are ready for discussion as we have to be mindful of our limited time, and we need to focus it where it has the most impact. If you would like us to spend some time working on this issue, please spend some time making this a substantial and quality ticket description.

    When describing your concern, please focus on the aspects that matter. There's no need to duplicate parts of our code in the description or use excessive summarization or bullet lists. Instead, use rather links if you want to point out subtle details that matter in the specific context. Avoid conflicting requests such as asking for guidance and then answering questions yourself, as such descriptions neglect raising a ticket in the first place.

    Concise, thoughtful explanations of your decision-making process are far more valuable than detailed restatements of the code.

    Our change #3441 surfaced a few constellations that are not suitable for eager cache warming such as this one causing type erasure. Our introspection deliberately uses Class as objects for auditing are raw classes themselves. Another occurence is the isEntity check that considers key and value types while getRequiredEntity only considers the value type. This is something we have to address.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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