junit-team/junit5 · error · ParameterResolutionException

Discovered multiple competing ParameterResolvers for…

Error message

Discovered multiple competing ParameterResolvers for parameter [%s] in %s [%s]: %s

What it means

Thrown as ParameterResolutionException when two or more ParameterResolver extensions report supportsParameter(...) == true for the same parameter. JUnit refuses to guess which resolver wins and aborts the invocation listing every competing resolver.

Solutions

  1. Make the custom resolver's supportsParameter more specific so it stops claiming parameters owned by other resolvers (narrow by annotation, type, position).
  2. Disable one of the competing resolvers via junit.jupiter.execution.extensions.enabled.extension.types filtering.
  3. Remove the duplicate registration (e.g. @ExtendWith present on both the class and a base class).

Example fix

// before
class WideResolver implements ParameterResolver {
    public boolean supportsParameter(ParameterContext pc, ExtensionContext ec) {
        return true; // claims everything, conflicts with built-ins
    }
}
// after
class MyServiceResolver implements ParameterResolver {
    public boolean supportsParameter(ParameterContext pc, ExtensionContext ec) {
        return pc.getParameter().getType() == MyService.class;
    }
}
Defensive patterns

Strategy: validation

Validate before calling

long count = Stream.of(MyTest.class, MyTest.class.getSuperclass())
    .flatMap(c -> Stream.of(c.getAnnotations()))
    .filter(a -> a instanceof ExtendWith)
    .flatMap(a -> Stream.of(((ExtendWith) a).value()))
    .filter(c -> ParameterResolver.class.isAssignableFrom(c))
    .count();
if (count > 1) throw new IllegalStateException("multiple ParameterResolvers detected");

Prevention

When it happens

Trigger: matchingResolvers.size() > 1 after filtering the extension registry - e.g. two extensions both claim the same parameter type. The message enumerates them via StringUtils.defaultToString for each.

Common situations: Two libraries both register a resolver for the same type (e.g. a generic Object resolver, two TestInfo-style extensions); a developer writes a custom resolver that overlaps with a built-in (TestInfo, TempDir) one; duplicate @ExtendWith on class and field.

Related errors


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

Appendix: source

Thrown at junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/ParameterResolutionUtils.java:145

			// @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);

			logger.trace(
				() -> "ParameterResolver [%s] resolved a value of type [%s] for parameter [%s] in %s [%s].".formatted(
					resolver.getClass().getName(), (value != null ? value.getClass().getTypeName() : null),
					parameterContext.getParameter(), asLabel(executable), executable.toGenericString()));

			return value;
		}
		catch (ParameterResolutionException ex) {
			throw ex;
		}

View on GitHub (pinned to f070c699a0)