elastic/elasticsearch · error · IllegalArgumentException
{} is not a valid Entitlement class name. A valid class name
Error message
{} is not a valid Entitlement class name. A valid class name must end with 'Entitlement' What it means
Thrown by PolicyParser.buildEntitlementNameFromClass when an Entitlement subclass's simple name does not end with the literal suffix 'Entitlement'. The parser derives the policy key (e.g. 'files_entitlement') by stripping that suffix and splitting on camel-case; without it the naming convention is broken and the class cannot be referenced by name in policy files.
Source
Thrown at libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyParser.java:78
WriteAllSystemPropertiesEntitlement.class,
WriteSystemPropertiesEntitlement.class
).collect(Collectors.toUnmodifiableMap(PolicyParser::buildEntitlementNameFromClass, Function.identity()));
private static final Map<Class<? extends Entitlement>, String> EXTERNAL_ENTITLEMENT_NAMES_BY_CLASS =
EXTERNAL_ENTITLEMENT_CLASSES_BY_NAME.entrySet()
.stream()
.collect(Collectors.toUnmodifiableMap(Map.Entry::getValue, Map.Entry::getKey));
protected final XContentParser policyParser;
protected final String policyName;
private final boolean isExternalPlugin;
private final Map<String, Class<? extends Entitlement>> externalEntitlements;
static String buildEntitlementNameFromClass(Class<? extends Entitlement> entitlementClass) {
var entitlementClassName = entitlementClass.getSimpleName();
if (entitlementClassName.endsWith("Entitlement") == false) {
throw new IllegalArgumentException(
entitlementClassName + " is not a valid Entitlement class name. A valid class name must end with 'Entitlement'"
);
}
var strippedClassName = entitlementClassName.substring(0, entitlementClassName.indexOf("Entitlement"));
return Arrays.stream(strippedClassName.split("(?=\\p{Lu})"))
.filter(Predicate.not(String::isEmpty))
.map(s -> s.toLowerCase(Locale.ROOT))
.collect(Collectors.joining("_"));
}
public static String getEntitlementName(Class<? extends Entitlement> entitlementClass) {
return EXTERNAL_ENTITLEMENT_NAMES_BY_CLASS.get(entitlementClass);
}
public PolicyParser(InputStream inputStream, String policyName, boolean isExternalPlugin) throws IOException {
this(inputStream, policyName, isExternalPlugin, EXTERNAL_ENTITLEMENT_CLASSES_BY_NAME);
}View on GitHub (pinned to db6a809a66)
Solutions
- Rename the class so its simple name ends with 'Entitlement' (e.g. MyAccessEntitlement).
- Rebuild the plugin so the renamed class is picked up.
- Ensure any registered external entitlement class follows the '<Name>Entitlement' convention.
Example fix
// before
public class MyAccess implements Entitlement { ... }
// after
public class MyAccessEntitlement implements Entitlement { ... } Defensive patterns
Strategy: validation
Validate before calling
// Assert naming convention before registering a custom entitlement
String simple = entitlementClass.getSimpleName();
if (!simple.endsWith("Entitlement")) {
throw new IllegalArgumentException(simple + " must end with 'Entitlement'");
} Type guard
boolean isValidEntitlementName(Class<? extends Entitlement> c) {
return c.getSimpleName().endsWith("Entitlement");
} Prevention
- Adopt the '<Name>Entitlement' naming convention for all custom entitlement classes.
- Add a unit test that validates every registered entitlement class name.
When it happens
Trigger: An external plugin registers a custom Entitlement subclass whose getSimpleName() does not end with 'Entitlement'. buildEntitlementNameFromClass is called during the static EXTERNAL_ENTITLEMENT_CLASSES_BY_NAME map construction, so this fails at class-registration time.
Common situations: Naming a custom entitlement class 'MyAccess' instead of 'MyAccessEntitlement'; a refactor dropped the suffix; copy-pasting a base class and forgetting the naming convention.
Related errors
- Error occurred when inspecting class: {}; SerializedLambda r
- Error occurred when inspecting class: {}
- Proxy fallback only supports instance method references; no
- Method reference passed to 'calling()' does not belong to {}
- No constructor found on {} with parameter types {}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/cfffa312f1b04056.
Report an issue: GitHub.