junit-team/junit5 · error · JUnitException

Failed to inject parameter value into field: %s

Error message

Failed to inject parameter value into field: %s

What it means

Thrown by ResolverFacade.setField() when Field.set() fails during injection of a resolved parameter value into a @Parameter-annotated field of a @ParameterizedClass test instance. The underlying exception (typically IllegalAccessException due to final fields, type mismatch, or security manager restrictions) is attached as the cause. The %s placeholder is the Field's toString() representation including declaring class and field name.

Source

Thrown at junit-jupiter-params/src/main/java/org/junit/jupiter/params/ResolverFacade.java:313

						invocationIndex, resolutionCache));
		}
	}

	private Stream<ParameterDeclaration> getAllParameterDeclarations() {
		return Stream.concat(this.indexedParameterDeclarations.declarationsByIndex.values().stream(),
			aggregatorParameters.stream());
	}

	private void setField(Object testInstance, FieldParameterDeclaration declaration, ExtensionContext extensionContext,
			EvaluatedArgumentSet arguments, int invocationIndex, ResolutionCache resolutionCache) {

		Object argument = resolutionCache.resolve(declaration,
			() -> resolve(declaration, extensionContext, arguments, invocationIndex, Optional.empty()));
		try {
			declaration.getField().set(testInstance, argument);
		}
		catch (Exception e) {
			throw new JUnitException("Failed to inject parameter value into field: " + declaration.getField(), e);
		}
	}

	private @Nullable Object resolve(ResolvableParameterDeclaration parameterDeclaration,
			ExtensionContext extensionContext, EvaluatedArgumentSet arguments, int invocationIndex,
			Optional<ParameterContext> parameterContext) {
		Resolver resolver = getResolver(extensionContext, parameterDeclaration);
		return parameterDeclaration.resolve(resolver, extensionContext, arguments, invocationIndex, parameterContext);
	}

	private Resolver getResolver(ExtensionContext extensionContext, ResolvableParameterDeclaration declaration) {
		return this.resolvers.computeIfAbsent(declaration, __ -> this.aggregatorParameters.contains(declaration) //
				? createAggregator(declaration, extensionContext) //
				: createConverter(declaration, extensionContext));
	}

	private int toLogicalIndex(ParameterContext parameterContext) {
		int index = parameterContext.getIndex() - this.parameterIndexOffset;

View on GitHub (pinned to f070c699a0)

Solutions

  1. Remove the 'final' modifier from @Parameter-annotated fields — JUnit needs to write to them
  2. Ensure the field's type is compatible with the argument source's value type (or add an ArgumentConverter)
  3. On JDK 16+, add --add-opens flags to the JVM if accessing fields across module boundaries
  4. Make the field accessible (public) or ensure the test class is open for reflection (Kotlin: use @Open or the kotlin-spring plugin)

Example fix

// before — final field blocks injection
@ParameterizedClass
class MyTest {
    @Parameter
    private final int value;
}

// after — remove final
@ParameterizedClass
class MyTest {
    @Parameter
    private int value;
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate that @Parameter fields are not final and are accessible
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

static void validateParameterFields(Class<?> testClass) {
    for (Field f : testClass.getDeclaredFields()) {
        if (f.isAnnotationPresent(org.junit.jupiter.params.Parameter.class)) {
            if (Modifier.isFinal(f.getModifiers())) {
                throw new IllegalStateException(
                    "@Parameter field " + f.getName() + " must not be final");
            }
            f.setAccessible(true); // ensure access on JDK 16+
        }
    }
}

Prevention

When it happens

Trigger: A @Parameter-annotated field is declared final, making Field.set() fail. A @Parameter field's declared type doesn't match the resolved argument type and auto boxing/unboxing can't bridge it. The field belongs to a class loaded by a different class loader with restrictive access. A security manager blocks reflective field access on JDK 17+ without --add-opens.

Common situations: Using @Parameter on a final field (common in record-style or immutable test classes). JDK 16+ strong encapsulation where reflective access to private fields of JDK classes or modules is denied. Kotlin test classes where fields have different accessibility semantics than expected by Java reflection.

Related errors


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