elastic/elasticsearch · error · IllegalArgumentException

[{}] using module [{}] found duplicate entitlement [{}]

Error message

[{}] using module [{}] found duplicate entitlement [{}]

What it means

Thrown by PolicyManager.validateEntitlementsPerModule when the same entitlement class (e.g. FilesEntitlement, OutboundNetworkEntitlement) appears more than once within a single module's entitlement list for a component. Each module may declare each entitlement type at most once; duplicates are rejected as they would create ambiguous policy.

Source

Thrown at libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java:293

        FileAccessTree.validateExclusivePaths(exclusivePaths, FileAccessTree.DEFAULT_COMPARISON);
        this.exclusivePaths = exclusivePaths;
        this.forbiddenPaths = createForbiddenPaths(pathLookup);
    }

    private static Map<String, List<Entitlement>> buildScopeEntitlementsMap(Policy policy) {
        return policy.scopes().stream().collect(toUnmodifiableMap(Scope::moduleName, Scope::entitlements));
    }

    private static void validateEntitlementsPerModule(
        String componentName,
        String moduleName,
        List<Entitlement> entitlements,
        List<ExclusiveFileEntitlement> exclusiveFileEntitlements
    ) {
        Set<Class<? extends Entitlement>> found = new HashSet<>();
        for (var e : entitlements) {
            if (found.contains(e.getClass())) {
                throw new IllegalArgumentException(
                    "[" + componentName + "] using module [" + moduleName + "] found duplicate entitlement [" + e.getClass().getName() + "]"
                );
            }
            found.add(e.getClass());
            if (e instanceof FilesEntitlement fe) {
                exclusiveFileEntitlements.add(new ExclusiveFileEntitlement(componentName, moduleName, fe));
            }
        }
    }

    protected ModuleEntitlements getEntitlements(Class<?> requestingClass) {
        return moduleEntitlementsMap.computeIfAbsent(requestingClass.getModule(), m -> computeEntitlements(requestingClass));
    }

    protected final ModuleEntitlements computeEntitlements(Class<?> requestingClass) {
        var policyScope = scopeResolver.apply(requestingClass);
        var componentName = policyScope.componentName();
        var moduleName = policyScope.moduleName();

View on GitHub (pinned to db6a809a66)

Solutions

  1. Open the named component's policy file and find the duplicate entitlement block under the named module.
  2. Merge the two duplicate entries into a single entitlement of that type (e.g. combine the two 'files' lists).
  3. Remove the redundant entry.

Example fix

// before
module: org.elasticsearch.foo
entitlements:
  - files: [{ path: /a }]
  - files: [{ path: /b }]

// after: one files entitlement
module: org.elasticsearch.foo
entitlements:
  - files: [{ path: /a }, { path: /b }]
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate: each entitlement type appears once per module
Map<String, Set<Class<?>>> seen = new HashMap<>();
for (var e : moduleEntitlements) {
  var set = seen.computeIfAbsent(moduleName, k -> new HashSet<>());
  if (!set.add(e.getClass())) {
    throw new IllegalArgumentException("duplicate " + e.getClass().getSimpleName() + " in " + moduleName);
  }
}

Prevention

When it happens

Trigger: Iterating a module's entitlements, the 'found' set already contains e.getClass() when the same class is encountered a second time. The message names the component, the module, and the duplicated entitlement class.

Common situations: A policy YAML lists two 'files:' blocks under the same module; copy-paste added a second 'outbound_network:' under one module; merging policy fragments without de-duplicating.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/13777f0019e63beb. Report an issue: GitHub.