hibernate/hibernate-orm · error · AnnotationException

Error processing @TypeBinderType annotation

Error message

Error processing @TypeBinderType annotation '%s' for embeddable type '%s'

What it means

Hibernate throws this AnnotationException while binding an @Embeddable class when a custom binder registered through @TypeBinderType fails. The exception only wraps the real failure: the original exception thrown inside your TypeBinder.bind() implementation (or while instantiating the binder) is attached as the cause. Fix the cause, not this message.

Solutions

  1. Inspect the exception cause chain (getCause()) - the real failure is inside your TypeBinder.bind() implementation, not in Hibernate
  2. Step through your binder in a debugger during Metadata/SessionFactory build to find the failing line
  3. Make the binder handle the Component (embeddable) case, not just PersistentClass/entity
  4. Give the binder class a public no-arg constructor and verify its generic type argument matches the annotation type

Example fix

// before
public class TenantIdBinder implements TypeBinder<TenantScoped> {
    public void bind(TenantScoped ann, MetadataBuildingContext ctx, Component embeddable) {
        // NPE when the embeddable has no owner set yet
        embeddable.getOwner().getTable().addColumn( column( ann ) );
    }
}

// after
public class TenantIdBinder implements TypeBinder<TenantScoped> {
    public void bind(TenantScoped ann, MetadataBuildingContext ctx, Component embeddable) {
        if ( embeddable.getOwner() == null ) {
            throw new IllegalArgumentException(
                "@TenantScoped requires the embeddable to have an owner" );
        }
        embeddable.getOwner().getTable().addColumn( column( ann ) );
    }
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
    SessionFactory sf = metadata.getSessionFactoryBuilder().build();
}
catch ( AnnotationException e ) {
    // the binder's real failure is nested - unwrap and report the cause
    Throwable cause = e.getCause() != null ? e.getCause() : e;
    throw new IllegalStateException( "Custom @TypeBinderType binder failed during bootstrap: "
        + cause.getMessage(), cause );
}

Prevention

When it happens

Trigger: A user-defined annotation meta-annotated with @TypeBinderType is placed on an @Embeddable class. During metadata building Binders.callTypeBinder(Annotation, Class<A>, Component, MetadataBuildingContext) reflects the binder, instantiates it, and calls bind(annotation, context, embeddable); any exception from bind(), from the no-arg constructor, or from the type-argument check is caught and rethrown wrapped in this message.

Common situations: A custom TypeBinder written for entities is reused on embeddables and calls entity-only APIs; the binder dereferences null annotation attributes or an unpopulated Component; the binder class lacks a public no-arg constructor; a Hibernate upgrade changed the TypeBinder API so old binder code throws NoSuchMethodError or similar.

Related errors


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

Appendix: source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/Binders.java:36

import static org.hibernate.internal.util.GenericsHelper.typeArguments;

/**
 * @author Gavin King
 * @since 7.3
 */
public class Binders {
	static <A extends Annotation> void callTypeBinder(
			Annotation annotation, Class<A> annotationType,
			Component embeddable,
			MetadataBuildingContext context) {
		try {
			typeBinder( annotationType )
					.bind( annotationType.cast( annotation ),
							context, embeddable );
		}
		catch (Exception e) {
			throw new AnnotationException(
					"Error processing @TypeBinderType annotation '%s' for embeddable type '%s'"
							.formatted( annotation, embeddable.getComponentClassName() ), e );
		}
	}

	static <A extends Annotation> void callTypeBinder(
			Annotation annotation, Class<A> annotationType,
			PersistentClass entity,
			MetadataBuildingContext context) {
		try {
			typeBinder( annotationType )
					.bind( annotationType.cast( annotation ),
							context, entity );
		}
		catch (Exception e) {
			throw new AnnotationException(
					"Error processing @TypeBinderType annotation '%s' for entity type '%s'"
							.formatted( annotation, entity.getClassName() ), e );

View on GitHub (pinned to fad1729dce)