junit-team/junit5 · error · ArgumentConversionException

No built-in converter for source type

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 (so string-based conversion can't be attempted). The DefaultArgumentConverter can only convert: (1) source already assignable to target, (2) String source via ConversionSupport. For any other source type that doesn't match, there is no built-in converter. The message includes both source and target type names.

Solutions

  1. Ensure the ArgumentsProvider returns values whose types are assignable to (or String-convertible to) the parameter types
  2. Register a custom ArgumentConverter via @ConvertWith to handle the specific source-to-target conversion
  3. If using @MethodSource, verify the returned argument types match the parameter declarations exactly
  4. Convert arguments to Strings in the provider if the built-in String-based converters can handle the target type

Example fix

// before — provider returns wrong type
@ParameterizedTest
@MethodSource("data")
void test(LocalDate date) { }

static Stream<Arguments> data() {
    return Stream.of(Arguments.of(java.util.Date.from(Instant.now()))); // Date ≠ LocalDate
}

// after — return matching types or add a converter
static Stream<Arguments> data() {
    return Stream.of(Arguments.of(LocalDate.now())); // types match
}

// OR use @ConvertWith:
@ParameterizedTest
@MethodSource("data")
void test(@ConvertWith(DateToLocalDateConverter.class) LocalDate date) { }
Defensive patterns

Strategy: validation

Validate before calling

// Validate argument types against parameter types before running
import org.junit.platform.commons.util.ReflectionUtils;

static boolean isConvertible(Object source, Class<?> targetType) {
    if (source == null) return !targetType.isPrimitive();
    if (ReflectionUtils.isAssignableTo(source, targetType)) return true;
    if (source instanceof String) return true; // built-in String conversion may handle it
    return false; // no built-in converter for non-String, non-assignable
}

// Usage: validate all arguments from the provider before returning them

Type guard

// Type guard for checking source-target convertibility
static boolean canConvert(Object source, Class<?> target) {
    if (source == null) return !target.isPrimitive();
    if (target.isAssignableFrom(source.getClass())) return true;
    return source instanceof String; // String can attempt built-in conversion
}

Prevention

When it happens

Trigger: Pass a non-String, non-assignable object as a parameterized test argument. For example: a BigDecimal parameter with a LocalDate argument source, or an Integer parameter with a Double value. This occurs when a custom ArgumentsProvider returns objects whose types don't match the parameter declarations and aren't Strings.

Common situations: Custom ArgumentsProvider implementations that return domain objects instead of Strings or directly-matching types. Argument sources that read from JSON/databases and return typed objects that don't match the test parameter declarations. Mixing @MethodSource providers that return different object types than expected.

Related errors


AI-assisted analysis of junit-team/junit5@f070c699a0 (2026-08-11). Data as JSON: /api/errors/e15492bad74d487b. Report an issue: GitHub.

Appendix: 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 f070c699a0)