apache/maven · error · ComponentConfigurationException
Cannot find permitted subclass '{}' for sealed type {}
Error message
Cannot find permitted subclass '{}' for sealed type {} What it means
A plugin/component configuration uses an implementation='...' hint to choose an implementation of a sealed type, but the hint matches none of the sealed type's permitted subclasses. EnhancedConfigurationConverter.getPermittedSubclass() compares the hint against each permitted subclass's binary name, canonical name, and simple name; zero matches raise this error, chained onto the original lookup failure.
Source
Thrown at impl/maven-core/src/main/java/org/apache/maven/configuration/internal/EnhancedConfigurationConverter.java:150
final Class<?> type,
final String implementation,
final PlexusConfiguration configuration,
final ComponentConfigurationException cause)
throws ComponentConfigurationException {
final List<Class<?>> matches = new ArrayList<>();
for (Class<?> permittedSubclass : type.getPermittedSubclasses()) {
if (implementation.equals(permittedSubclass.getName())
|| implementation.equals(permittedSubclass.getCanonicalName())
|| implementation.equals(permittedSubclass.getSimpleName())) {
matches.add(permittedSubclass);
}
}
if (matches.size() == 1) {
return matches.get(0);
}
if (matches.isEmpty()) {
throw new ComponentConfigurationException(
configuration,
"Cannot find permitted subclass '" + implementation + "' for sealed type " + type.getName(),
cause);
}
matches.sort(Comparator.comparing(Class::getName));
throw new ComponentConfigurationException(
configuration,
"Implementation hint '" + implementation + "' is ambiguous for sealed type " + type.getName() + ": "
+ matches.stream().map(Class::getName).toList(),
cause);
}
public void processConfiguration(
final ConverterLookup lookup,
final Object bean,
final ClassLoader loader,
final PlexusConfiguration configuration,View on GitHub (pinned to e4093d4e12)
Solutions
- Use the fully qualified name of a class actually listed by the sealed type (check its javadoc or Class.getPermittedSubclasses())
- Fix typos in the implementation attribute value
- Omit the implementation attribute to let the converter use its default instantiation path
- Align the plugin/library versions so the intended implementation is permitted by the sealed type
Example fix
<!-- before --> <param implementation="DefaultHandler"/> <!-- after: fully qualified permitted subclass --> <param implementation="org.example.api.sealed.FileHandler"/>
Defensive patterns
Strategy: validation
Validate before calling
// Verify an implementation hint resolves before applying configuration
Class<?> sealed = MySealedInterface.class;
String hint = "org.example.api.sealed.FileHandler"; // from the configuration
boolean permitted = Arrays.stream(sealed.getPermittedSubclasses())
.map(Class::getName)
.anyMatch(hint::equals);
if (!permitted) {
throw new IllegalArgumentException("implementation '" + hint + "' is not permitted by " + sealed.getName());
} Type guard
static Optional<Class<?>> resolvePermitted(Class<?> sealed, String hint) {
List<Class<?>> matches = Arrays.stream(sealed.getPermittedSubclasses())
.filter(c -> hint.equals(c.getName()) || hint.equals(c.getCanonicalName()) || hint.equals(c.getSimpleName()))
.toList();
return matches.size() == 1 ? Optional.of(matches.get(0)) : Optional.empty();
} Prevention
- Always use fully qualified names in implementation attributes
- After upgrading a library with sealed configuration types, re-check the permits list
- Validate the hint against getPermittedSubclasses() in tests that assert configuration validity
When it happens
Trigger: Configuration like <param implementation="MyImpl"> where the target type is a sealed interface and 'MyImpl' equals no Class in type.getPermittedSubclasses(): typo, wrong package, or a class that exists in the plugin realm but is not on the sealed type's permits list.
Common situations: Upgrading a library whose sealed interface replaced or removed a permitted subclass; configuration samples copied from a different library version; using a simple name when the intended class lives in another package.
Related errors
- Implementation hint '{}' is ambiguous for sealed type {}: {}
- Cannot set default
- Cannot find '{}' in {}
- Cannot read metadata from '{}'
- Unable to lookup org.eclipse.aether.RepositorySystem
AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21).
Data as JSON: /api/errors/b9f5f0a2c0888569.
Report an issue: GitHub.