spring-projects/spring-framework · error · IllegalStateException

Failed to find Java constructor for Kotlin primary construct

Error message

Failed to find Java constructor for Kotlin primary constructor: ${clazz.getName()}

What it means

Thrown inside the private KotlinDelegate.findPrimaryConstructor (IllegalStateException) when the class is detected as Kotlin and a primary constructor exists, but kotlin.reflect.jvm.ReflectJvmMapping.getJavaConstructor returned null - the Kotlin-to-Java constructor mapping could not be resolved. This is an internal Spring failure to bridge Kotlin reflection to a Java Constructor, surfaced when BeanUtils.instantiateClass resolves constructor args for a Kotlin bean.

Source

Thrown at spring-beans/src/main/java/org/springframework/beans/BeanUtils.java:889

		 * https://kotlinlang.org/docs/reference/classes.html#constructors</a>
		 */
		@SuppressWarnings("unchecked")
		public static <T> @Nullable Constructor<T> findPrimaryConstructor(Class<T> clazz) {
			try {
				KClass<T> kClass = JvmClassMappingKt.getKotlinClass(clazz);
				KFunction<T> primaryCtor = KClasses.getPrimaryConstructor(kClass);
				if (primaryCtor == null) {
					return null;
				}
				if (KotlinDetector.isInlineClass(clazz)) {
					Constructor<?>[] constructors = clazz.getDeclaredConstructors();
					Assert.state(constructors.length == 1,
							"Kotlin value classes annotated with @JvmInline are expected to have a single JVM constructor");
					return (Constructor<T>) constructors[0];
				}
				Constructor<T> constructor = ReflectJvmMapping.getJavaConstructor(primaryCtor);
				if (constructor == null) {
					throw new IllegalStateException(
							"Failed to find Java constructor for Kotlin primary constructor: " + clazz.getName());
				}
				return constructor;
			}
			catch (UnsupportedOperationException ex) {
				return null;
			}
		}

		/**
		 * Instantiate a Kotlin class using the provided constructor.
		 * @param ctor the constructor of the Kotlin class to instantiate
		 * @param args the constructor arguments to apply
		 * (use {@code null} for unspecified parameter if needed)
		 */
		public static <T> T instantiateClass(Constructor<T> ctor, @Nullable Object... args)
				throws IllegalAccessException, InvocationTargetException, InstantiationException {

View on GitHub (pinned to e8729d0438)

Solutions

  1. Ensure kotlin-reflect version exactly matches the Kotlin stdlib version used to compile the class.
  2. If the class does not need primary-constructor resolution, annotate it with a plain Java-style constructor or @JvmOverloads so Spring falls back to Java resolution.
  3. Disable bytecode shrinking/obfuscation for Kotlin metadata, or add keep rules for constructors.
  4. Report to Spring if reproducible with aligned versions - getJavaConstructor returning null for a valid primary constructor is a bridge bug.

Example fix

// before: kotlin-reflect 1.6 on classpath, bean compiled with Kotlin 1.9
implementation "org.jetbrains.kotlin:kotlin-reflect:1.6.21"

// after: align reflect to the compiler
implementation "org.jetbrains.kotlin:kotlin-reflect:1.9.24"
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.24"
Defensive patterns

Strategy: validation

Validate before calling

// Confirm kotlin-reflect is present and version-aligned before instantiation
try {
    Class<?> kd = Class.forName("kotlin.reflect.jvm.ReflectJvmMapping");
    // optionally compare KotlinVersion to compiled metadata
} catch (ClassNotFoundException e) {
    throw new IllegalStateException("kotlin-reflect missing on classpath");
}
Constructor<?> c = BeanUtils.findPrimaryConstructor(clazz);
if (c == null) {
    // fall back: use a declared constructor explicitly
    c = clazz.getDeclaredConstructors()[0];
}

Type guard

// Verify the class actually has a resolvable Java constructor before Spring touches it
static boolean isKotlinBeanInstantiable(Class<?> clazz) {
    if (!KotlinDetector.isKotlinPresent() || !KotlinDetector.isKotlinType(clazz)) return true;
    Constructor<?> c = BeanUtils.findPrimaryConstructor(clazz);
    return c != null;
}

Try / catch

try {
    Constructor<T> ctor = BeanUtils.findPrimaryConstructor(clazz);
    return BeanUtils.instantiateClass(ctor == null ? clazz.getDeclaredConstructor() : ctor);
} catch (IllegalStateException ex) {
    if (ex.getMessage().contains("Failed to find Java constructor for Kotlin")) {
        // fall back to a manually chosen declared constructor
        Constructor<T> fallback = clazz.getDeclaredConstructors()[0];
        ReflectionUtils.makeAccessible(fallback);
        return fallback.newInstance();
    }
    throw ex;
}

Prevention

When it happens

Trigger: BeanUtils.findPrimaryConstructor(clazz) on a Kotlin class whose primary constructor is present in Kotlin metadata but has no resolvable Java Constructor (obfuscated bytecode, unusual compiler-generated synthetic constructors, mismatched kotlin-reflect runtime version vs. the Kotlin compiler that produced the class).

Common situations: Upgrading the Kotlin compiler without bumping kotlin-reflect on the classpath; R8/ProGuard stripping the constructor metadata; Kotlin classes compiled with experimental language versions; Spring trying to autowire a Kotlin data class when kotlin-reflect is missing or a different version.

Related errors


AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04). Data as JSON: /data/errors/86c95a01a93e095f.json. Report an issue: GitHub.