hibernate/hibernate-orm · error · UnsupportedOperationException
AnyType not supported as part of cache key!
Error message
AnyType not supported as part of cache key!
What it means
AnyType (the type Hibernate assigns to @Any/@ManyToAny mappings) overrides Type.disassemble(Object, SessionFactoryImplementor) to throw UnsupportedOperationException, because an any-typed value (discriminator + id pair pointing at different entities) has no stable representation usable as a second-level cache key. The two-argument disassemble is invoked by DefaultCacheKeysFactory when materializing entity-id and natural-id cache keys, so the error surfaces the first time a cached entity whose key includes an @Any value is read or written through the cache.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/AnyType.java:363
public Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException {
if ( value == null ) {
return null;
}
else {
return new ObjectTypeCacheEntry(
session.bestGuessEntityName( value ),
getEntityIdentifierIfNotUnsaved(
session.bestGuessEntityName( value ),
value,
session
)
);
}
}
@Override
public Serializable disassemble(Object value, SessionFactoryImplementor sessionFactory) throws HibernateException {
throw new UnsupportedOperationException( "AnyType not supported as part of cache key!" );
}
@Override
public Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map<Object, Object> copyCache)
throws HibernateException {
if ( original == null ) {
return null;
}
else {
final String entityName = session.bestGuessEntityName( original );
final Object id = getEntityIdentifierIfNotUnsaved( entityName, original, session );
return session.internalLoad( entityName, id, eager, false );
}
}
// CompositeType implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@OverrideView on GitHub (pinned to fad1729dce)
Solutions
- Remove the @Any attribute from the natural id / composite key and key the cache on a plain value (e.g. the id column alone).
- Replace @Any with a concrete @ManyToOne (or several typed associations) if the association must participate in cache keys.
- If polymorphism is required, model the reference as a first-class association table (join entity with discriminator + fk) instead of @Any.
- Exclude the entity from second-level caching if the @Any must stay in the key position.
Example fix
// before
@Entity
@Cacheable
public class Document {
@Id Long id;
@Any
@AnyDiscriminator(MapKeyDiscriminatorType.STRING)
@AnyKeyDefaultDiscriminator("USER")
@JoinColumn(name = "owner_type")
@Column(name = "owner_id")
private Party owner; // used in @NaturalId below
@NaturalId
OwnerRef naturalKey; // component containing the @Any
}
// after: key the cache on plain columns only
@Entity
@Cacheable
public class Document {
@Id Long id;
@Any(...) // kept as an ordinary attribute, NOT part of the natural id
private Party owner;
@NaturalId
@Column(name = "doc_code")
private String docCode;
} Defensive patterns
Strategy: validation
Validate before calling
// Fail fast at startup: cached entities must not have @Any inside id/natural-id components
Metamodel mm = emf.getMetamodel();
for (EntityType<?> et : mm.getEntities()) {
if (et.getJavaType().isAnnotationPresent(Cacheable.class)) {
for (Attribute<?, ?> attr : et.getAttributes()) {
Member m = attr.getJavaMember();
if (m instanceof Field f && (f.isAnnotationPresent(Any.class)
|| f.isAnnotationPresent(ManyToAny.class))
&& (attr.isCollection() || isInNaturalId(et, attr))) {
throw new IllegalStateException(
et.getName() + "." + attr.getName()
+ " is @Any and cannot participate in a cache key");
}
}
}
} Prevention
- Keep @Any mappings out of identifiers and @NaturalId members; they are value pairs, not cache-key-able scalars.
- Add a mapping smoke test that loads/caches one instance of every cached entity to surface cache-key errors at build time.
- Document the limitation wherever @Any is introduced in code review.
When it happens
Trigger: An @Any or @ManyToAny mapping used as an entity identifier, as part of a composite id, or as a member of a @NaturalId on an entity that is second-level cached (@Cacheable/@Cache); also an @Any embedded in a @Embedded component that participates in a natural id, since ComponentType.disassemble recurses into property types. Calls to Type.disassemble(value, sessionFactory) in custom code on an AnyType hit the same throw.
Common situations: Legacy mappings using <any> inside a composite natural key; adding @Cacheable to an entity that already had a polymorphic @Any reference in its natural id; migrating from Hibernate 5 where a different cache-key path silently serialized the value.
Related errors
- Caching was not configured for entity natural id:
- CollectionType not supported as part of cache key!
- transformation of <any/> as part of <join/> (secondary-table
- Table '${table}' has no column named '${column}' matching th
- Property '${property}' belongs to an entity subclass and may
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/1ce63f44c1ef74a0.
Report an issue: GitHub.