junit-team/junit5 · error · ArgumentConversionException

Cannot convert to %s: %s

Error message

Cannot convert to %s: %s

What it means

Thrown by JavaTimeArgumentConverter when the requested target type is not one of the supported java.time temporal types registered in TEMPORAL_QUERIES. The converter looks up a TemporalQuery by target class; if no entry exists it cannot know how to parse the input string into that type. This is a hard precondition failure of @JavaTimeConversionPattern.

Source

Thrown at junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/JavaTimeArgumentConverter.java:67

		queries.put(YearMonth.class, YearMonth::from);
		queries.put(ZonedDateTime.class, ZonedDateTime::from);
		TEMPORAL_QUERIES = Collections.unmodifiableMap(queries);
	}

	@Override
	protected @Nullable Object convert(@Nullable Object input, Class<?> targetClass,
			JavaTimeConversionPattern annotation) {

		if (input == null) {
			if (annotation.nullable()) {
				return null;
			}
			throw new ArgumentConversionException(
				"Cannot convert null to " + targetClass.getName() + "; consider setting 'nullable = true'");
		}
		TemporalQuery<?> temporalQuery = TEMPORAL_QUERIES.get(targetClass);
		if (temporalQuery == null) {
			throw new ArgumentConversionException("Cannot convert to " + targetClass.getName() + ": " + input);
		}
		String pattern = annotation.value();
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
		return formatter.parse(input.toString(), temporalQuery);
	}

}

View on GitHub (pinned to f070c699a0)

Solutions

  1. Change the parameter type to a supported java.time type such as LocalDate, LocalTime, LocalDateTime, Instant, Year, YearMonth, MonthDay, or OffsetDateTime.
  2. If you must use a non-temporal type, write a custom ArgumentConverter via @ConvertWith instead of @JavaTimeConversionPattern.
  3. Verify the import of the parameter type is from java.time and not java.util/java.sql.
  4. Check the conversion pattern string in @JavaTimeConversionPattern matches the input data format.

Example fix

// before
@ParameterizedTest
@CsvSource("2024-01-01")
void test(@JavaTimeConversionPattern("yyyy-MM-dd") java.util.Date date) { }

// after
@ParameterizedTest
@CsvSource("2024-01-01")
void test(@JavaTimeConversionPattern("yyyy-MM-dd") LocalDate date) { }
Defensive patterns

Strategy: validation

Validate before calling

// Before binding the parameter, confirm the target type is a supported temporal type
private static final Set<Class<?>> SUPPORTED = Set.of(
    LocalDate.class, LocalTime.class, LocalDateTime.class,
    Year.class, YearMonth.class, MonthDay.class, Instant.class,
    OffsetDateTime.class, OffsetTime.class, ZonedDateTime.class);

if (!SUPPORTED.contains(targetType)) {
    throw new IllegalArgumentException("Unsupported temporal type: " + targetType);
}

Type guard

static boolean isSupportedJavaTimeType(Class<?> c) {
    return c == LocalDate.class || c == LocalTime.class || c == LocalDateTime.class
        || c == Year.class || c == YearMonth.class || c == MonthDay.class
        || c == Instant.class || c == OffsetDateTime.class || c == OffsetTime.class
        || c == ZonedDateTime.class;
}

Prevention

When it happens

Trigger: Annotating a @ParameterizedTest parameter with @JavaTimeConversionPattern and declaring a target type that is not in the TEMPORAL_QUERIES map (e.g. java.util.Date, java.sql.Timestamp, or a custom temporal class). The converter reaches the `if (temporalQuery == null)` branch and throws.

Common situations: Migrating parameterized tests from older date types to java.time and forgetting that only LocalDate, LocalTime, LocalDateTime, YearMonth, etc. are supported. Declaring a legacy Date/Calendar parameter expecting the converter to handle it. Typo or wrong import causing the resolved target class to differ from the intended java.time type.

Related errors


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