junit-team/junit5 · error · JUnitException

Failed to format display name for parameterized test. See…

Error message

Failed to format display name for parameterized test. See nested exception for further details.

What it means

Thrown at runtime (during actual test invocation) when formatting the display name fails, as opposed to error 47 which fails at parse time. The format() method calls formatSafely() which iterates through the PartialFormatter segments and appends to a StringBuffer. If a formatter fails — e.g., a MessageFormat placeholder references argument index {5} but only 3 arguments were provided — the exception is wrapped in this JUnitException with the original cause.

Solutions

  1. Ensure all argument sets provide a consistent number of arguments that matches the display name pattern's placeholders
  2. Use the {arguments} or {arguments-with-names} placeholder which adapts to the actual argument count, rather than fixed indices like {0}, {1}
  3. Inspect the nested cause for the specific index or formatting error
  4. Validate argument set shapes in your ArgumentsProvider before returning them

Example fix

// before — pattern expects 3 args but some rows have 2
@ParameterizedTest(name = "{0} {1} {2}")
@CsvSource({ "a,b,c", "d,e" })
void test(String x, String y, String z) { }

// after — use adaptive placeholder
@ParameterizedTest(name = "#{index} {arguments}")
@CsvSource({ "a,b,c", "d,e" })
void test(String x, String y, @Parameter(values = "default") String z) { }
Defensive patterns

Strategy: validation

Validate before calling

// Validate that all argument sets have enough values for the display name pattern
import java.util.regex.Matcher;
import java.util.regex.Pattern;

static int maxPlaceholderIndex(String pattern) {
    Pattern p = Pattern.compile("\\{(\\d+)");
    Matcher m = p.matcher(pattern);
    int max = -1;
    while (m.find()) {
        max = Math.max(max, Integer.parseInt(m.group(1)));
    }
    return max;
}

// Ensure: every Arguments set has at least (maxPlaceholderIndex + 1) values
// If not, use {arguments} instead of {0}, {1}, etc.

Prevention

When it happens

Trigger: The display name pattern references more arguments than are actually supplied for a particular invocation. For example, @ParameterizedTest(name="{0} {1} {2}") but an Arguments source provides only 2 values for some invocations. An ArgumentSet with fewer columns than the pattern expects.

Common situations: Parameterized tests with variable-length argument sets (some rows have more columns than others). Display name patterns designed for the maximum argument count but some sources provide fewer. CSV sources with ragged rows where some lines have fewer fields. Custom Arguments providers with inconsistent argument counts.

Related errors


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

Appendix: source

Thrown at junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedInvocationNameFormatter.java:105

			ParameterizedDeclarationContext<?> declarationContext, int argumentMaxLength) {
		try {
			this.partialFormatters = parse(pattern, displayName, declarationContext, argumentMaxLength);
		}
		catch (Exception ex) {
			String message = "The display name pattern defined for the parameterized test is invalid. "
					+ "See nested exception for further details.";
			throw new JUnitException(message, ex);
		}
	}

	String format(int invocationIndex, EvaluatedArgumentSet arguments, boolean quoteTextArguments) {
		try {
			return formatSafely(invocationIndex, arguments, quoteTextArguments);
		}
		catch (Exception ex) {
			String message = "Failed to format display name for parameterized test. "
					+ "See nested exception for further details.";
			throw new JUnitException(message, ex);
		}
	}

	@SuppressWarnings("JdkObsolete")
	private String formatSafely(int invocationIndex, EvaluatedArgumentSet arguments, boolean quoteTextArguments) {
		ArgumentsContext context = new ArgumentsContext(invocationIndex, arguments.getConsumedArguments(),
			arguments.getName(), quoteTextArguments);
		StringBuffer result = new StringBuffer(); // used instead of StringBuilder so MessageFormat can append directly
		for (PartialFormatter partialFormatter : this.partialFormatters) {
			partialFormatter.append(context, result);
		}
		return result.toString();
	}

	private PartialFormatter[] parse(String pattern, String displayName,
			ParameterizedDeclarationContext<?> declarationContext, int argumentMaxLength) {

		List<PartialFormatter> result = new ArrayList<>();

View on GitHub (pinned to f070c699a0)