hibernate/hibernate-orm · error · AnnotationException
Annotation '@" + annotation.annotationType().getName() + "'
Error message
Annotation '@" + annotation.annotationType().getName() + "' did not expose a String-valued 'value' member
What it means
When binding Jakarta Data repository methods, QueryBinder.staticQueryString reflectively reads the value() member of any annotation whose type name is jakarta.data.Query. annotationValue invokes value() via reflection and casts the result to String; a ClassCastException (non-String member) or ReflectiveOperationException (no such member / inaccessible) throws AnnotationException naming the annotation FQN. In practice this means the jakarta.data.Query on the classpath is not the shape Hibernate expects.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java:497
else {
for ( var annotation : methodDetails.getDirectAnnotationUsages() ) {
if ( JAKARTA_DATA_QUERY.equals( annotation.annotationType().getName() ) ) {
return annotationValue( annotation );
}
}
return null;
}
}
private static String annotationValue(Annotation annotation) {
try {
return (String)
annotation.annotationType()
.getMethod( "value" )
.invoke( annotation );
}
catch (ClassCastException | ReflectiveOperationException e) {
throw new AnnotationException(
"Annotation '@" + annotation.annotationType().getName()
+ "' did not expose a String-valued 'value' member",
e
);
}
}
private static void bindStaticNativeQuery(
ClassDetails classDetails,
MethodDetails methodDetails,
MetadataBuildingContext context,
ModelsContext modelsContext) {
final var query = methodDetails.getAnnotationUsage( NativeQuery.class, modelsContext );
if ( query != null ) {
final String registrationName = staticQueryName( classDetails, methodDetails );
if ( BOOT_LOGGER.isTraceEnabled() ) {
BOOT_LOGGER.bindingNamedNativeQuery( registrationName, query.value().replace( '\n', ' ' ) );
}View on GitHub (pinned to fad1729dce)
Solutions
- Align the jakarta.data artifact version with the one your Hibernate version supports (check Hibernate's bill of materials / documentation for the paired release).
- Run dependency:tree / dependencies and exclude the stray jakarta.data jar so exactly one, correct version is present.
- Remove any custom annotation wrongly declared in the jakarta.data package namespace.
- If you did not intend Jakarta Data repository support, remove the @Query-annotated repository from the scanned entities/packages.
Example fix
// before (Maven: conflicting jakarta.data versions resolved to a milestone build) <dependency> <groupId>jakarta.data</groupId> <artifactId>jakarta.data-api</artifactId> <version>1.0.0-m8</version> </dependency> // after (align with the version your Hibernate release supports) <dependency> <groupId>jakarta.data</groupId> <artifactId>jakarta.data-api</artifactId> <version>1.0.1</version> </dependency>
Defensive patterns
Strategy: type-guard
Validate before calling
// at startup, assert the jakarta.data.Query on the classpath has a String value() member
Class<?> q = Class.forName("jakarta.data.Query");
if (q.getMethod("value").getReturnType() != String.class) {
throw new IllegalStateException("Incompatible jakarta.data artifact: Query.value() is not String");
} Type guard
boolean isCompatibleJakartaDataQuery(ClassLoader cl) throws ClassNotFoundException {
return Class.forName("jakarta.data.Query", false, cl)
.getMethod("value")
.getReturnType() == String.class;
} Try / catch
try {
sessionFactory = bootstrap();
} catch (AnnotationException e) {
// message names the annotation that failed reflection - treat as classpath/alignment bug
failBuild("Check jakarta.data version alignment: " + e.getMessage());
} Prevention
- Let Hibernate's BOM pin the jakarta.data version; do not override it casually.
- Run a dependency convergence check so only one jakarta.data jar resolves.
- Never declare your own annotations in the jakarta.data package.
When it happens
Trigger: A repository interface method carries an annotation named jakarta.data.Query whose value() is missing, non-String, or inaccessible — typically an incompatible or shadowing jakarta.data artifact version next to Hibernate 7's Jakarta Data support. Fires during model processing of repository interfaces (bindStaticNativeQuery/staticQueryString path), i.e. at bootstrap.
Common situations: Mixed jakarta.data versions on the classpath (milestone vs release API where value() changed); a vendor BOM pulling a different jakarta.data-api than Hibernate's supported one; a custom annotation accidentally placed in the jakarta.data package; Gradle/Maven dependency conflict resolution picking the wrong jar.
Related errors
- Unable to initialize EventType map
- Error calling Value#setTypeUsingReflection: containingClassN
- Unable to perform extended enhancement - No unique field [%s
- Multiple active MetadataBuilder definitions were discovered
- Unable to determine JAR Url from <url>. Cause: <cause>
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/b4f6d9da82ef7733.
Report an issue: GitHub.