junit-team/junit5 · error · ArgumentConversionException
%s cannot convert to type [%s]. Only target type [%s] is sup
Error message
%s cannot convert to type [%s]. Only target type [%s] is supported.
What it means
Thrown by TypedArgumentConverter (as ArgumentConversionException) during argument injection when the actual parameter type is not assignable from the converter's declared targetType. The converter was built to produce one type but the @ParameterizedTest parameter declares an incompatible type.
Source
Thrown at junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/TypedArgumentConverter.java:79
public final @Nullable Object convert(@Nullable Object source, FieldContext context)
throws ArgumentConversionException {
return convert(source, context.getField().getType());
}
private T convert(@Nullable Object source, Class<?> actualTargetType) {
if (source == null) {
return convert(null);
}
if (!this.sourceType.isInstance(source)) {
String message = "%s cannot convert objects of type [%s]. Only source objects of type [%s] are supported.".formatted(
getClass().getSimpleName(), source.getClass().getTypeName(), this.sourceType.getTypeName());
throw new ArgumentConversionException(message);
}
if (!ReflectionUtils.isAssignableTo(this.targetType, actualTargetType)) {
String message = "%s cannot convert to type [%s]. Only target type [%s] is supported.".formatted(
getClass().getSimpleName(), actualTargetType.getTypeName(), this.targetType.getTypeName());
throw new ArgumentConversionException(message);
}
return convert(this.sourceType.cast(source));
}
/**
* Convert the supplied {@code source} object of type {@code S} into an object
* of type {@code T}.
*
* @param source the source object to convert; may be {@code null}
* @return the converted object; may be {@code null} but only if the target
* type is a reference type
* @throws ArgumentConversionException if an error occurs during the
* conversion
*/
protected abstract T convert(@Nullable S source) throws ArgumentConversionException;
}
View on GitHub (pinned to 956246301e)
Solutions
- Align the @ParameterizedTest parameter type with the converter's declared targetType (or vice versa).
- If the converter must satisfy several targets, make targetType a common supertype or switch to a plain ArgumentConverter instead of TypedArgumentConverter.
- Double-check the super(sourceType, targetType) call in the converter constructor matches the real parameter type.
Example fix
// before
@ParameterizedTest
@CsvSource({ "42" })
void test(@ConvertWith(ToIntConverter.class) Long n) { }
// ToIntConverter calls super(String.class, Integer.class)
// after
@ParameterizedTest
@CsvSource({ "42" })
void test(@ConvertWith(ToIntConverter.class) Integer n) { } Defensive patterns
Strategy: validation
Validate before calling
// Before registering a TypedArgumentConverter, assert type compatibility.
Class<?> declaredTarget = Integer.class; // what the converter was built for
Class<?> parameterType = method.getParameterTypes()[i];
if (!declaredTarget.isAssignableFrom(parameterType)
&& !parameterType.isAssignableFrom(declaredTarget)) {
throw new IllegalStateException(
"Converter target " + declaredTarget + " is incompatible with parameter " + parameterType);
} Type guard
// Narrow to a converter known to match the parameter type.
static <S, T> TypedArgumentConverter<S, T> forType(
Class<S> source, Class<T> target, Class<?> parameterType) {
if (!target.isAssignableFrom(parameterType)
&& !parameterType.isAssignableFrom(target)) {
throw new IllegalArgumentException("type mismatch: " + target + " vs " + parameterType);
}
return new TypedArgumentConverter<>(source, target) {
@Override protected T convert(S s) { return null; }
};
} Try / catch
try {
// invoke the parameterized test / conversion
} catch (ArgumentConversionException e) {
if (e.getMessage().contains("cannot convert to type")) {
// log and align the parameter type with the converter's target type
} else throw e;
} Prevention
- Keep the converter's targetType and the parameter type next to each other in code reviews.
- Add a unit test that constructs the converter and asserts convert() works for the exact parameter type.
- Prefer SimpleArgumentConverter or a custom ArgumentConverter when one converter must serve several target types.
When it happens
Trigger: A TypedArgumentConverter subclass (registered via @ConvertWith, or internally by @JavaTimeConversionPattern etc.) is applied to a parameter whose declared type differs from the targetType passed into the super(sourceType, targetType) constructor. E.g. a converter declared for Integer applied to a `long`/`Long` parameter, or a String->Instant converter applied to a LocalDate parameter.
Common situations: Copy-pasting a converter between parameterized tests with different parameter types; changing a parameter type without updating the converter; wrapper vs primitive mismatch; generic converter reused across targets.
Related errors
- @EmptySource cannot provide an empty argument %s: [%s] is no
- No built-in converter for source type %s and target type %s
- %s cannot convert objects of type [%s]. Only source objects
- Failed to parse CSV input configured via ${annotation}
- Pattern compilation failed for a regular expression supplied
AI-assisted analysis of junit-team/junit5@956246301e (2026-08-04).
Data as JSON: /data/errors/cef2814e4d05e7bb.json.
Report an issue: GitHub.