junit-team/junit5 · error · ArgumentConversionException

No built-in converter for source type %s and target type %s

Error message

No built-in converter for source type %s and target type %s

What it means

Thrown by DefaultArgumentConverter.convert() when the source object is not null, not assignable to the target type, and not a String. The built-in converter only handles String-to-target conversions (via ConversionSupport); non-String objects that are not already the target type have no conversion path.

Source

Thrown at junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/DefaultArgumentConverter.java:97

					"Cannot convert null to primitive value of type " + targetType.getTypeName());
			}
			return null;
		}

		if (ReflectionUtils.isAssignableTo(source, targetType)) {
			return source;
		}

		if (source instanceof String string) {
			try {
				return convert(string, targetType, classLoader);
			}
			catch (ConversionException ex) {
				throw new ArgumentConversionException(ex.getMessage(), ex);
			}
		}

		throw new ArgumentConversionException("No built-in converter for source type %s and target type %s".formatted(
			source.getClass().getTypeName(), targetType.getTypeName()));
	}

	@Nullable
	Object convert(@Nullable String source, Class<?> targetType, ClassLoader classLoader) {
		return ConversionSupport.convert(source, targetType, classLoader);
	}

}

View on GitHub (pinned to 956246301e)

Solutions

  1. Provide a @ConvertWith(MyConverter.class) on the parameter to handle the custom type conversion
  2. Change the @MethodSource to provide the argument as a String if the target type has a built-in String converter
  3. Align the source object type with the parameter type (provide the exact type the parameter expects)
  4. Implement a custom ArgumentConverter or SimpleArgumentConverter for the specific source-to-target mapping

Example fix

// before
@ParameterizedTest
@MethodSource("provider")
void test(LocalDate date) { }
static Stream<Arguments> provider() {
    return Stream.of(Arguments.of(12345)); // Integer -> LocalDate: no converter
}

// after
@ParameterizedTest
@MethodSource("provider")
void test(LocalDate date) { }
static Stream<Arguments> provider() {
    return Stream.of(Arguments.of("2024-01-15")); // String -> LocalDate: built-in
}
Defensive patterns

Strategy: validation

Validate before calling

// Check if the source type is String or assignable before relying on default conversion:
static boolean canConvertByDefault(Object source, Class<?> targetType) {
    if (source == null) return !targetType.isPrimitive();
    if (targetType.isAssignableFrom(source.getClass())) return true;
    return source instanceof String; // String has built-in conversion paths
}
if (!canConvertByDefault(arg, targetType)) {
    throw new IllegalStateException("Need a custom @ConvertWith converter for "
        + source.getClass() + " -> " + targetType);
}

Prevention

When it happens

Trigger: A @ParameterizedTest or @Parameter field whose source provides a non-String object (e.g., Integer, enum, custom POJO from a @MethodSource) and the parameter type is a different, non-assignable type with no @ConvertWith converter. For example, a @MethodSource providing an Integer for a LocalDate parameter.

Common situations: A @MethodSource returning Arguments.of(myObject) where myObject is a custom type and the test method parameter is a different type. Mixing object sources (non-String) with parameter types that need conversion but have no custom converter registered. Providing an enum or POJO where a primitive or temporal type is expected.

Related errors


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