hibernate/hibernate-orm · error · EnhancementException

Unable to perform extended enhancement - No unique field [%s

Error message

Unable to perform extended enhancement - No unique field [%s] defined by [%s]

What it means

During extended enhancement, after resolving the owner type of a field instruction, FieldAccessEnhancer.findField() looks for exactly one declared field matching both name and descriptor (named(name).and(hasDescriptor(desc))) walking the hierarchy. If the filtered list does not contain exactly one element - typically zero because the owner type resolved from the classpath is a different version whose field has a different descriptor/signature - it throws EnhancementException('No unique field [<name>] defined by [<owner>]').

Source

Thrown at hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldAccessEnhancer.java:131

	}

	private TypeDescription findDeclaredType(String name) {
		//Classpool#describe does not accept '/' in the description name as it expects a class name
		final String cleanedName = name.replace( '/', '.' );
		final var resolution = classPool.describe( cleanedName );
		if ( !resolution.isResolved() ) {
			throw new EnhancementException( String.format(
					"Unable to perform extended enhancement - Unable to locate [%s]",
					cleanedName
			) );
		}
		return resolution.resolve();
	}

	private AnnotatedFieldDescription findField(TypeDescription declaredOwnedType, String name, String desc) {
		final var fields = findFields( declaredOwnedType, name, desc );
		if ( fields.size() != 1 ) {
			throw new EnhancementException( String.format(
					"Unable to perform extended enhancement - No unique field [%s] defined by [%s]",
					name,
					declaredOwnedType.getName()
			) );
		}
		return new AnnotatedFieldDescription( enhancementContext, fields.getOnly() );
	}

	private static @Nonnull FieldList<?> findFields(TypeDescription declaredOwnedType, String name, String desc) {
		TypeDefinition ownerType = declaredOwnedType;
		final var fieldFilter = named( name ).and( hasDescriptor( desc ) );
		FieldList<?> fields = ownerType.getDeclaredFields().filter( fieldFilter );
		// Look in the superclasses if necessary
		while ( fields.isEmpty() && ownerType.getSuperClass() != null ) {
			ownerType = ownerType.getSuperClass();
			fields = ownerType.getDeclaredFields().filter( fieldFilter );
		}
		return fields;

View on GitHub (pinned to fad1729dce)

Solutions

  1. Align the enhancement classpath with the exact versions the entity classes were compiled against (dependencyManagement/lockfile) so the resolved field descriptor matches.
  2. Check for duplicate classes (same FQCN) across jars on the enhancement classpath and evict the stale copy.
  3. Disable extended enhancement if it is not strictly required - the error only occurs on that path.
  4. Use the message's owner type + field name to identify which artifact must be version-aligned.

Example fix

# before
# entity compiled against lib-2.0 (field: Optional<X> x), enhancement classpath has lib-1.9 (field: X x)
# -> findFields matches 0 -> 'No unique field [x] defined by [com.lib.Owner]'

# after
# gradle
configurations.enhanceClasspath { resolutionStrategy { force 'com.lib:lib:2.0' } } # or align via platform/BOM
Defensive patterns

Strategy: fallback

Validate before calling

// pre-flight: the enhancement classpath must contain the same owner-type versions the classes were compiled against
static boolean fieldDescriptorsMatch(ClassLoader cl, String owner, String field, String expectedDesc) throws Exception {
    Class<?> c = Class.forName( owner, false, cl );
    for ( var f : c.getDeclaredFields() ) {
        if ( f.getName().equals( field ) ) { return descriptorOf( f.getType() ).equals( expectedDesc ); }
    }
    return false;
}

Prevention

When it happens

Trigger: enableExtendedEnhancement(true) while the classpath holds a different version of the owner type than the one the class was compiled against: a field's type changed between versions (so the descriptor differs), the field was renamed/removed, or duplicate classes with conflicting field signatures are both visible.

Common situations: Conflicting dependency versions on the enhancement classpath (the classic 'two versions of the same library' problem surfacing as a descriptor mismatch); upgrading one library whose API changed a field type while the enhancer resolves the other; shaded jars bundling stale copies of a class.

Related errors


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