hibernate/hibernate-orm · error · IllegalArgumentException
Unknown callback annotation : {}
Error message
Unknown callback annotation : {} What it means
Thrown by CallbackType.fromAnnotation() as an IllegalArgumentException when the annotation passed in is not one of the recognized JPA lifecycle callback annotations (PrePersist, PostPersist, PreRemove, PostRemove, PreUpdate, PostUpdate, PostLoad, or Hibernate's PreDelete/PostDelete/PreMerge/PostMerge/PreUpsert variants). It is a defensive guard in the enum's annotation-resolution helper, not a mapping validator.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackType.java:113
if ( PreRemove.class.equals( ann ) ) {
return PRE_REMOVE;
}
if ( PostRemove.class.equals( ann ) ) {
return POST_REMOVE;
}
if ( PreDelete.class.equals( ann ) ) {
return PRE_DELETE;
}
if ( PostDelete.class.equals( ann ) ) {
return POST_DELETE;
}
if ( PreMerge.class.equals( ann ) ) {
return PRE_MERGE;
}
if ( PostLoad.class.equals( ann ) ) {
return POST_LOAD;
}
throw new IllegalArgumentException( "Unknown callback annotation : " + ann );
}
/// The callback annotation type corresponding to this lifecycle callback type.
public Class<? extends Annotation> getCallbackAnnotation() {
return switch ( this ) {
case PRE_PERSIST -> PrePersist.class;
case PRE_UPDATE -> PreUpdate.class;
case PRE_REMOVE -> PreRemove.class;
case PRE_INSERT -> PreInsert.class;
case PRE_DELETE -> PreDelete.class;
case PRE_MERGE -> PreMerge.class;
case PRE_UPSERT -> PreUpsert.class;
case POST_PERSIST -> PostPersist.class;
case POST_UPDATE -> PostUpdate.class;
case POST_REMOVE -> PostRemove.class;
case POST_INSERT -> PostInsert.class;
case POST_DELETE -> PostDelete.class;
case POST_UPSERT -> PostUpsert.class;View on GitHub (pinned to fad1729dce)
Solutions
- Filter to known callback annotations before calling fromAnnotation() - check against CallbackType values or the annotation set it documents.
- Make sure your entities use jakarta.persistence.* lifecycle annotations, not the legacy javax.persistence.* ones.
- If extending Hibernate's callback resolution, handle unknown annotations explicitly instead of delegating them.
Example fix
// before
for (var ann : method.getAnnotations()) {
CallbackType t = CallbackType.fromAnnotation(ann.annotationType()); // throws on @Transactional
}
// after
for (var ann : method.getAnnotations()) {
Optional<CallbackType> t = CallbackType.resolveFrom(ann.annotationType());
t.ifPresent(type -> register(type, method));
} Defensive patterns
Strategy: type-guard
Type guard
boolean isCallbackAnnotation(Class<? extends Annotation> a) {
return java.lang.reflect.Annotation.class.isAssignableFrom(a)
&& (a.getName().startsWith("jakarta.persistence.") || a.getName().startsWith("org.hibernate.annotations."))
&& java.util.Set.of("PrePersist","PostPersist","PreRemove","PostRemove","PreUpdate","PostUpdate","PostLoad").contains(a.getSimpleName());
} Prevention
- Filter annotations through an explicit allowlist of lifecycle callbacks before resolving CallbackType.
- Keep a single persistence namespace (jakarta.*) on the classpath; exclude legacy javax.persistence jars.
When it happens
Trigger: Calling CallbackType.fromAnnotation() (or an integration that delegates to it) with a non-callback annotation - e.g. a custom audit annotation, @Entity, or a jakarta vs javax variant of a lifecycle annotation mixed on the classpath.
Common situations: Integrator/enhancement code iterating annotations on entity listeners and forwarding every annotation to this helper; applications stuck with javax.persistence annotations while Hibernate expects jakarta.persistence ones; custom annotation processors that pass through every field/method annotation.
Related errors
- Class '<componentClassName>' is an '@Embeddable' type and ma
- Property '<propertyName>' may not be annotated '@BatchSize'
- One to many association '<propertyName>' was annotated '@Col
- Collection '<propertyName>' was annotated '@Collate'
- Root entity '<entityName>' is annotated '@DiscriminatorOptio
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/cc374c79c83fa9b7.
Report an issue: GitHub.