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

  1. Align the @ParameterizedTest parameter type with the converter's declared targetType (or vice versa).
  2. If the converter must satisfy several targets, make targetType a common supertype or switch to a plain ArgumentConverter instead of TypedArgumentConverter.
  3. 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

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


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