spring-projects/spring-framework · error · IllegalStateException
No primary or single unique constructor found for {clazz}
Error message
No primary or single unique constructor found for {clazz} What it means
Thrown as IllegalStateException (not a BeansException) by getResolvableConstructor at BeanUtils.java:265 when a class has multiple public constructors, no Kotlin primary constructor, is not a record, and has no no-arg default constructor either — i.e. there is no single unambiguous constructor Spring can pick. The algorithm in getResolvableConstructor exhausted primary-constructor, single-public, single-non-public, and default-constructor lookup.
Source
Thrown at spring-beans/src/main/java/org/springframework/beans/BeanUtils.java:265
else if (ctors.length == 0) {
// No public constructors -> check non-public
ctors = clazz.getDeclaredConstructors();
if (ctors.length == 1) {
// A single non-public constructor, for example, from a non-public record type
return (Constructor<T>) ctors[0];
}
}
// Several constructors -> let's try to take the default constructor
try {
return clazz.getDeclaredConstructor();
}
catch (NoSuchMethodException ex) {
// Giving up...
}
// No unique constructor at all
throw new IllegalStateException("No primary or single unique constructor found for " + clazz);
}
/**
* Return the primary constructor of the provided class. For Kotlin classes, this
* returns the Java constructor corresponding to the Kotlin primary constructor
* (as defined in the Kotlin specification). For Java records, this returns the
* canonical constructor. Otherwise, this simply returns {@code null}.
* @param clazz the class to check
* @since 5.0
* @see <a href="https://kotlinlang.org/docs/reference/classes.html#constructors">Kotlin constructors</a>
* @see <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-8.html#jls-8.10.4">Record constructor declarations</a>
*/
public static <T> @Nullable Constructor<T> findPrimaryConstructor(Class<T> clazz) {
Assert.notNull(clazz, "Class must not be null");
if (KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(clazz)) {
return KotlinDelegate.findPrimaryConstructor(clazz);
}
if (clazz.isRecord()) {View on GitHub (pinned to 69bf83ad71)
Solutions
- Annotate the intended constructor with @ConstructorProperties or make it the only public constructor.
- Add a no-arg default constructor so the fallback in getResolvableConstructor succeeds.
- Reduce to a single public constructor (make others non-public).
- Use an explicit @Bean factory method or explicit Constructor argument instead of relying on auto-resolution.
Example fix
// before: ambiguous
public class Props {
public Props(String a) {}
public Props(String a, int b) {}
}
// after
public class Props {
public Props() {}
public Props(String a, int b) { ... }
} Defensive patterns
Strategy: validation
Validate before calling
Constructor<?> c = BeanUtils.findPrimaryConstructor(clazz);
if (c == null) {
Constructor<?>[] publics = clazz.getConstructors();
if (publics.length != 1) {
// expect multiple -> ensure a no-arg ctor exists or annotate one
try { clazz.getDeclaredConstructor(); }
catch (NoSuchMethodException e) { /* will fail */ }
}
} Type guard
static boolean hasResolvableConstructor(Class<?> c) {
if (BeanUtils.findPrimaryConstructor(c) != null) return true;
if (c.getConstructors().length == 1) return true;
try { c.getDeclaredConstructor(); return true; }
catch (NoSuchMethodException e) { return false; }
} Try / catch
try {
BeanUtils.getResolvableConstructor(clazz);
} catch (IllegalStateException ex) {
// ambiguous -> supply explicit constructor to the binder/factory
Constructor<?> chosen = clazz.getDeclaredConstructor(String.class, int.class);
} Prevention
- Give @ConfigurationProperties/value classes a single public constructor or a no-arg constructor.
- Use @ConstructorProperties to declare the canonical constructor for binding.
- Make overloaded constructors non-public so a single public one is unambiguous.
- Validate constructor structure in unit tests for binding targets.
When it happens
Trigger: Calling getResolvableConstructor(clazz) (used by @ConfigurationProperties, constructor binding, data binding) on a class with two or more public constructors and no no-arg constructor. None of the disambiguation heuristics (single public, single non-public, default) apply, so resolution fails.
Common situations: @ConfigurationProperties class with overloaded constructors; constructor-binding DTOs with multiple explicit constructors; domain entities with several public constructors and no default; Spring Boot 3 / Spring 6 stricter constructor binding that requires an unambiguous constructor.
Related errors
- Illegal arguments for constructor
- Constructor threw exception
- Cannot resolve method '{methodName}' to a unique method. Att
- Invalid property '{propertyName}' of bean class [{beanClass.
- Specified class is an interface
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/51e59ee675b2aa1a.
Report an issue: GitHub.