hibernate/hibernate-orm · error · AnnotationException

Class or package level '@NamedNativeQuery' annotation must s

Error message

Class or package level '@NamedNativeQuery' annotation must specify a 'name'

What it means

QueryBinder.bindNativeQuery registers a jakarta.persistence @NamedNativeQuery; a blank registrationName throws AnnotationException at bootstrap. The name is the key used by entityManager.createNamedQuery(name, ...) and must be non-empty.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/QueryBinder.java:170

				BOOT_LOGGER.bindingNamedNativeMutation( registrationName,
						annotation.statement().replace( '\n', ' ' ) );
			}

			final var definition = NamedNativeMutationDefinitionImpl.from( annotation, location );
			context.getMetadataCollector().addNamedNativeQuery( definition );
		}
	}

	public static void bindNativeQuery(
			NamedNativeQuery namedNativeQuery,
			MetadataBuildingContext context,
			AnnotationTarget location,
			boolean isDefault) {
		if ( namedNativeQuery != null ) {
			final String registrationName = namedNativeQuery.name();
			final String queryString = namedNativeQuery.query();
			if ( registrationName.isBlank() ) {
				throw new AnnotationException(
						"Class or package level '@NamedNativeQuery' annotation must specify a 'name'" );
			}

			if ( BOOT_LOGGER.isTraceEnabled() ) {
				BOOT_LOGGER.bindingNamedNativeQuery( registrationName,
						queryString.replace( '\n', ' ' ) );
			}

			final var collector = context.getMetadataCollector();
			final String resultSetMappingName;
			if ( hasInlineResultSetMapping( namedNativeQuery ) ) {
				resultSetMappingName = registrationName;
				if ( !namedNativeQuery.resultSetMapping().isBlank() ) {
					throw new AnnotationException(
							"Named native query '%s' specified both 'resultSetMapping' and an inline result set mapping"
									.formatted( registrationName )
					);
				}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Assign a unique non-blank name to the @NamedNativeQuery.
  2. Verify no merge/refactor left an empty name attribute; grep for name = "" across annotations.
  3. Store names in constants covered by a non-blank assertion test.

Example fix

// before
@NamedNativeQuery(name = "", query = "SELECT * FROM person WHERE email = :email")

// after
@NamedNativeQuery(name = "Person.findByEmailNative", query = "SELECT * FROM person WHERE email = :email")
Defensive patterns

Strategy: validation

Validate before calling

@Test void nativeQueriesHaveNames() {
    for (NamedNativeQuery q : Order.class.getAnnotationsByType(NamedNativeQuery.class)) {
        assertTrue(!q.name().isBlank(), "@NamedNativeQuery needs a name");
    }
}

Try / catch

try {
    metadata = sources.buildMetadata();
} catch (AnnotationException e) {
    failBuild("Named native query registration failed: " + e.getMessage());
}

Prevention

When it happens

Trigger: @NamedNativeQuery(name = "", query = "SELECT * FROM person") at class or package level; also a whitespace-only name. Thrown while binding annotations before any query executes.

Common situations: Splitting query text across lines and accidentally deleting the name; XML-less migration where name defaulted empty; duplicate annotations where one copy lost its name after merge conflicts.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/dd05dde15bd77949. Report an issue: GitHub.