elastic/elasticsearch · error · PolicyValidationException

invalid relative directory: {}, valid values: [config, data,

Error message

invalid relative directory: {}, valid values: [config, data, home]

What it means

Thrown by FilesEntitlement.parseBaseDir when the `relative_to` (or `basedir_if_relative`) value is not one of the recognised base-directory literals. Note: the switch actually accepts five values (config, data, home, shared_data, shared_repo) but the error message only documents three (config, data, home) by design — the shared_* dirs are intentionally undocumented because they are intended for Elasticsearch-internal modules only.

Source

Thrown at libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java:189

        } else if (platform.equals("macos")) {
            return Platform.MACOS;
        } else if (platform.equals("windows")) {
            return Platform.WINDOWS;
        } else {
            throw new PolicyValidationException("invalid platform: " + platform + ", valid values: [linux, macos, windows]");
        }
    }

    private static BaseDir parseBaseDir(String baseDir) {
        return switch (baseDir) {
            case "config" -> BaseDir.CONFIG;
            case "data" -> BaseDir.DATA;
            case "home" -> BaseDir.USER_HOME;
            case "shared_data" -> BaseDir.SHARED_DATA;
            // it would be nice to limit this to just ES modules, but we don't have a way to plumb that through to here
            // however, we still don't document in the error case below that shared_repo and shared_data is valid
            case "shared_repo" -> BaseDir.SHARED_REPO;
            default -> throw new PolicyValidationException(
                "invalid relative directory: " + baseDir + ", valid values: [config, data, home]"
            );
        };
    }

    @ExternalEntitlement(parameterNames = { "paths" }, esModulesOnly = false)
    @SuppressWarnings("unchecked")
    public static FilesEntitlement build(List<Object> paths) {
        if (paths == null || paths.isEmpty()) {
            throw new PolicyValidationException("must specify at least one path");
        }
        BiFunction<Map<String, Object>, String, String> checkString = (values, key) -> {
            Object value = values.remove(key);
            if (value == null) {
                return null;
            } else if (value instanceof String str) {
                return str;
            }

View on GitHub (pinned to db6a809a66)

Solutions

  1. For external plugins, use one of the documented values: "config", "data", or "home".
  2. If you are an Elasticsearch-internal module, "shared_data" and "shared_repo" are also accepted but intentionally undocumented in the error.
  3. Do not put a literal filesystem path in this field — it is a symbolic base-dir selector.

Example fix

// before
{ "relative_path": "logs", "relative_to": "/var/lib/es", "mode": "read_write" }

// after
{ "relative_path": "logs", "relative_to": "data", "mode": "read_write" }
Defensive patterns

Strategy: validation

Validate before calling

private static final Set<String> PUBLIC_BASE_DIRS = Set.of("config", "data", "home");
private static final Set<String> INTERNAL_BASE_DIRS = Set.of("shared_data", "shared_repo");
public static void validateBaseDir(String dir, boolean isExternalPlugin) {
    if (!PUBLIC_BASE_DIRS.contains(dir) && (!INTERNAL_BASE_DIRS.contains(dir) || isExternalPlugin)) {
        throw new IllegalArgumentException("invalid base dir: " + dir);
    }
}

Type guard

public static boolean isValidPublicBaseDir(String d) {
    return Set.of("config","data","home").contains(d);
}

Prevention

When it happens

Trigger: A files-entitlement entry sets `relative_to` or `basedir_if_relative` to an unrecognised literal (e.g. "logs", "tmp", "base", "root", or a typo like "conf").

Common situations: Guessing a directory name; using a path-like value ("/etc/elasticsearch") instead of the symbolic literal; external plugin author trying to use shared_data/shared_repo (which is reserved for ES modules); typo in the literal.

Related errors


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