junit-team/junit5 · error · JUnitException

Failed to find constructor for %s [%s]. Please ensure that a

Error message

Failed to find constructor for %s [%s]. Please ensure that a no-argument or a single constructor exists.

What it means

Thrown by ParameterizedTestSpiInstantiator.findBestConstructor() when instantiating a custom SPI implementation (ArgumentsProvider, ArgumentConverter, or ArgumentsAggregator) whose class has multiple constructors and none of them is a no-argument (default) constructor. The instantiator first checks for a single constructor (returns it regardless of arity), then checks for a no-arg constructor; if neither exists, this error is thrown.

Source

Thrown at junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestSpiInstantiator.java:72

		Constructor<?>[] constructors = implementationClass.getDeclaredConstructors();

		// Single constructor?
		if (constructors.length == 1) {
			return constructors[0];
		}
		// Find default constructor.
		for (Constructor<?> constructor : constructors) {
			if (constructor.getParameterCount() == 0) {
				return constructor;
			}
		}
		// Otherwise...
		String message = """
				Failed to find constructor for %s [%s]. \
				Please ensure that a no-argument or a single constructor exists.""".formatted(
			spiInterface.getSimpleName(), implementationClass.getName());
		throw new JUnitException(message);
	}

	private ParameterizedTestSpiInstantiator() {
	}

}

View on GitHub (pinned to 956246301e)

Solutions

  1. Add an explicit no-argument constructor to the custom SPI class
  2. If the class has exactly one constructor with parameters, remove extra constructors so there is a single constructor (the instantiator accepts any single-constructor class)
  3. Ensure the class is a top-level class or a static nested class (not a non-static inner class)

Example fix

// before
static class MyProvider implements ArgumentsProvider {
    MyProvider(String config) { }
    MyProvider(int x) { }
    // no no-arg constructor
    public Stream<? extends Arguments> provideArguments(ParameterDeclarations p, ExtensionContext c) { ... }
}

// after
static class MyProvider implements ArgumentsProvider {
    MyProvider() { } // no-arg constructor added
    public Stream<? extends Arguments> provideArguments(ParameterDeclarations p, ExtensionContext c) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate SPI class constructor structure before registering:
static void validateSpiClass(Class<?> implClass) {
    Constructor<?>[] ctors = implClass.getDeclaredConstructors();
    boolean hasNoArg = Arrays.stream(ctors).anyMatch(c -> c.getParameterCount() == 0);
    if (ctors.length > 1 && !hasNoArg) {
        throw new IllegalStateException(implClass.getName()
            + " must have a no-arg or single constructor");
    }
    if (implClass.isMemberClass() && !Modifier.isStatic(implClass.getModifiers())) {
        throw new IllegalStateException(implClass.getName() + " must be static nested or top-level");
    }
}

Prevention

When it happens

Trigger: Referencing a custom class via @ArgumentsSource(MyProvider.class), @ConvertWith(MyConverter.class), or @AggregateWith(MyAggregator.class) where that class declares multiple constructors and none has zero parameters. The SPI classes must be top-level or static nested classes with either a single constructor or an accessible no-arg constructor.

Common situations: Writing a custom ArgumentsProvider/ArgumentConverter with convenience constructors (e.g., a configuration constructor alongside a no-arg one) but forgetting the no-arg constructor, or adding a second constructor during refactoring. Using an inner (non-static) class as a provider, which also fails an earlier check.

Related errors


AI-assisted analysis of junit-team/junit5@956246301e (2026-08-04). Data as JSON: /data/errors/ff0470155cc8b298.json. Report an issue: GitHub.