elastic/elasticsearch · error · IllegalStateException

Unable to parse policy patch for layer [{}]

Error message

Unable to parse policy patch for layer [{}]

What it means

Wrapped exception from PolicyUtils.parseEncodedPolicyIfExists. It tries to base64-decode and JSON-parse a policy patch supplied (typically via a system property / agent arg) for a named layer; any failure during decode, parse, or scope validation is caught and rethrown as an IllegalStateException with this message and the original cause attached.

Source

Thrown at libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyUtils.java:119

            try {
                var versionedPolicy = decodeEncodedPolicy(encodedPolicy, layerName, externalPlugin);
                validatePolicyScopes(layerName, versionedPolicy.policy(), moduleNames, "<patch>");

                // Empty versions defaults to "any"
                if (versionedPolicy.versions().isEmpty() || versionedPolicy.versions().contains(version)) {
                    logger.info("Using policy patch for layer [{}]", layerName);
                    return versionedPolicy.policy();
                } else {
                    logger.warn(
                        "Found a policy patch with version mismatch. The patch will not be applied. "
                            + "Layer [{}]; policy versions [{}]; current version [{}]",
                        layerName,
                        String.join(",", versionedPolicy.versions()),
                        version
                    );
                }
            } catch (Exception e) {
                throw new IllegalStateException("Unable to parse policy patch for layer [" + layerName + "]", e);
            }
        }
        return null;
    }

    static VersionedPolicy decodeEncodedPolicy(String base64String, String layerName, boolean isExternalPlugin) throws IOException {
        byte[] policyDefinition = Base64.getDecoder().decode(base64String);
        return new PolicyParser(new ByteArrayInputStream(policyDefinition), layerName, isExternalPlugin).parseVersionedPolicy();
    }

    private static void validatePolicyScopes(String layerName, Policy policy, Set<String> moduleNames, String policyLocation) {
        // TODO: should this check actually be part of the parser?
        for (Scope scope : policy.scopes()) {
            if (moduleNames.contains(scope.moduleName()) == false) {
                throw new IllegalStateException(
                    Strings.format(
                        "Invalid module name in policy: layer [%s] does not have module [%s]; available modules [%s]; policy path [%s]",
                        layerName,

View on GitHub (pinned to db6a809a66)

Solutions

  1. Inspect the caused-by exception (the original IOException or PolicyParserException) for the real parse failure.
  2. Regenerate the base64 policy payload from the canonical JSON (base64 encode without line wrapping) and ensure the JSON parses standalone.
  3. If the failure is scope validation, confirm every module referenced in the policy exists in the layer's available module set.
  4. Verify the encoded string has no trailing whitespace or newline when injected via system property.

Example fix

// before
-Des.entitlements.policy_patch.mymodule=$(cat broken.json | base64)

// after
-Des.entitlements.policy_patch.mymodule=$(jq -c . valid-policy.json | base64 -w0)
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the base64 + JSON before injecting as a system property.
public static String encodePolicyPatch(Path policyJson) throws IOException {
    byte[] json = Files.readAllBytes(policyJson);
    // parse to confirm it's valid JSON / valid policy shape
    try (var in = new ByteArrayInputStream(json)) {
        new PolicyParser(in, "precheck", false).parsePolicy();
    }
    return Base64.getEncoder().encodeToString(json);
}

Try / catch

try {
    Policy p = PolicyUtils.parseEncodedPolicyIfExists(encoded, version, external, layerName, moduleNames);
} catch (IllegalStateException e) {
    // message: "Unable to parse policy patch for layer [...]"
    Throwable cause = e.getCause();
    log.error("policy patch for {} failed: {}", layerName, cause == null ? e : cause);
    // fall back to no patch (null) or fail fast depending on operator policy
}

Prevention

When it happens

Trigger: A non-null encodedPolicy string is supplied to parseEncodedPolicyIfExists but it is not valid base64, or its decoded JSON is not a valid policy, or scope validation against moduleNames fails. The layer name in the message identifies which plugin/module layer caused it.

Common situations: Setting an entitlement policy patch via JVM system property with a malformed base64 payload; shipping a plugin whose embedded policy JSON has a syntax error; version mismatch where decode succeeds but downstream policy validation throws; copy-pasting a truncated base64 blob.

Understand the failure class

Related errors


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