junit-team/junit5 · error · ParameterResolutionException
No ParameterResolver registered for parameter
Error message
No ParameterResolver registered for parameter [%s] in %s [%s].
What it means
Thrown as ParameterResolutionException when no registered ParameterResolver reports supportsParameter(...) == true for a parameter of a test constructor or test/lifecycle method. JUnit Jupiter resolves every parameter via extensions, so an unresolved parameter is fatal for that invocation.
Solutions
- Add @RegisterExtension/@ExtendWith for a ParameterResolver that handles the unresolved type.
- Switch the parameter to a built-in resolvable type (TestInfo, TestReporter, RepetitionInfo, ExtensionContext, TempDir) and read what you need from it.
- Fix a custom resolver's supportsParameter to return true for the relevant parameter context (check annotations, position, declaring executable).
Example fix
// before
@Test
void uses(UserService svc) { } // no resolver
// after - register a resolver that builds it
@RegisterExtension
static final UserServiceResolver resolver = new UserServiceResolver();
static class UserServiceResolver implements ParameterResolver {
@Override public boolean supportsParameter(ParameterContext pc, ExtensionContext ec) {
return pc.getParameter().getType() == UserService.class;
}
@Override public Object resolveParameter(ParameterContext pc, ExtensionContext ec) {
return new UserService();
}
} Defensive patterns
Strategy: validation
Validate before calling
List<ParameterResolver> resolvers = ServiceLoader.load(ParameterResolver.class).stream()
.map(p -> p.get())
.filter(r -> r.supportsParameter(parameterContext, extensionContext))
.toList();
if (resolvers.isEmpty()) {
throw new IllegalStateException("No resolver for parameter " + parameterContext.getParameter());
} Prevention
- Register a ParameterResolver for every non-builtin parameter type you inject.
- Use built-in types (TestInfo, TestReporter, ExtensionContext, TempDir) where possible.
- Double-check a custom resolver's supportsParameter covers the parameter context you expect.
When it happens
Trigger: resolveParameter filters the extensionRegistry stream of ParameterResolver to those that supportsParameter; if matchingResolvers.isEmpty(), the throw fires. Common with constructor/method parameters that no built-in or registered resolver handles (TestInfo, RepetitionInfo, TestReporter are built-in; arbitrary types need an extension).
Common situations: Asking for a domain object (UserService, RestClient) without a corresponding ParameterResolver; typo in a custom resolver's supportsParameter; a resolver that only handles certain parameter names/positions; using a parameter type supported only when an annotation is present but the annotation was forgotten.
Related errors
- Discovered multiple competing ParameterResolvers for…
- Failed to resolve parameter
- ParameterResolver [ ] resolved a value of type [ ] for…
- Can only resolve @TempDir
- Chain of InvocationInterceptors called invocation multiple…
AI-assisted analysis of junit-team/junit5@f070c699a0 (2026-08-11).
Data as JSON: /api/errors/080d945e97b86419.
Report an issue: GitHub.
Appendix: source
Thrown at junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ParameterResolutionUtils.java:134
for (int i = start; i < parameters.length; i++) {
ParameterContext parameterContext = new DefaultParameterContext(parameters[i], i, target);
values[i] = resolveParameter(parameterContext, executable, extensionContext, extensionRegistry);
}
return values;
}
private static @Nullable Object resolveParameter(ParameterContext parameterContext, Executable executable,
ExtensionContextSupplier extensionContext, ExtensionRegistry extensionRegistry) {
try {
// @formatter:off
List<ParameterResolver> matchingResolvers = extensionRegistry.stream(ParameterResolver.class)
.filter(resolver -> resolver.supportsParameter(parameterContext, extensionContext.get(resolver)))
.toList();
// @formatter:on
if (matchingResolvers.isEmpty()) {
throw new ParameterResolutionException(
"No ParameterResolver registered for parameter [%s] in %s [%s].".formatted(
parameterContext.getParameter(), asLabel(executable), executable.toGenericString()));
}
if (matchingResolvers.size() > 1) {
// @formatter:off
String resolvers = matchingResolvers.stream()
.map(StringUtils::defaultToString)
.collect(joining(", "));
// @formatter:on
throw new ParameterResolutionException(
"Discovered multiple competing ParameterResolvers for parameter [%s] in %s [%s]: %s".formatted(
parameterContext.getParameter(), asLabel(executable), executable.toGenericString(), resolvers));
}
ParameterResolver resolver = matchingResolvers.get(0);
Object value = resolver.resolveParameter(parameterContext, extensionContext.get(resolver));
validateResolvedType(parameterContext.getParameter(), value, executable, resolver);View on GitHub (pinned to f070c699a0)