{"record":{"id":"cc374c79c83fa9b7","repo":"hibernate/hibernate-orm","slug":"unknown-callback-annotation","errorCode":null,"errorMessage":"Unknown callback annotation : {}","messagePattern":"Unknown callback annotation : (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackType.java","lineNumber":113,"sourceCode":"\t\tif ( PreRemove.class.equals( ann ) ) {\n\t\t\treturn PRE_REMOVE;\n\t\t}\n\t\tif ( PostRemove.class.equals( ann ) ) {\n\t\t\treturn POST_REMOVE;\n\t\t}\n\t\tif ( PreDelete.class.equals( ann ) ) {\n\t\t\treturn PRE_DELETE;\n\t\t}\n\t\tif ( PostDelete.class.equals( ann ) ) {\n\t\t\treturn POST_DELETE;\n\t\t}\n\t\tif ( PreMerge.class.equals( ann ) ) {\n\t\t\treturn PRE_MERGE;\n\t\t}\n\t\tif ( PostLoad.class.equals( ann ) ) {\n\t\t\treturn POST_LOAD;\n\t\t}\n\t\tthrow new IllegalArgumentException( \"Unknown callback annotation : \" + ann );\n\t}\n\n\t/// The callback annotation type corresponding to this lifecycle callback type.\n\tpublic Class<? extends Annotation> getCallbackAnnotation() {\n\t\treturn switch ( this ) {\n\t\t\tcase PRE_PERSIST -> PrePersist.class;\n\t\t\tcase PRE_UPDATE -> PreUpdate.class;\n\t\t\tcase PRE_REMOVE -> PreRemove.class;\n\t\t\tcase PRE_INSERT -> PreInsert.class;\n\t\t\tcase PRE_DELETE -> PreDelete.class;\n\t\t\tcase PRE_MERGE -> PreMerge.class;\n\t\t\tcase PRE_UPSERT -> PreUpsert.class;\n\t\t\tcase POST_PERSIST -> PostPersist.class;\n\t\t\tcase POST_UPDATE -> PostUpdate.class;\n\t\t\tcase POST_REMOVE -> PostRemove.class;\n\t\t\tcase POST_INSERT -> PostInsert.class;\n\t\t\tcase POST_DELETE -> PostDelete.class;\n\t\t\tcase POST_UPSERT -> PostUpsert.class;","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackType.java#L95-L131","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nfor (var ann : method.getAnnotations()) {\n    CallbackType t = CallbackType.fromAnnotation(ann.annotationType()); // throws on @Transactional\n}\n\n// after\nfor (var ann : method.getAnnotations()) {\n    Optional<CallbackType> t = CallbackType.resolveFrom(ann.annotationType());\n    t.ifPresent(type -> register(type, method));\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"boolean isCallbackAnnotation(Class<? extends Annotation> a) {\n    return java.lang.reflect.Annotation.class.isAssignableFrom(a)\n        && (a.getName().startsWith(\"jakarta.persistence.\") || a.getName().startsWith(\"org.hibernate.annotations.\"))\n        && java.util.Set.of(\"PrePersist\",\"PostPersist\",\"PreRemove\",\"PostRemove\",\"PreUpdate\",\"PostUpdate\",\"PostLoad\").contains(a.getSimpleName());\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["hibernate","jpa","entity-lifecycle","callbacks","annotations"],"backgroundTag":"unsupported-annotation","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}