elastic/elasticsearch · error · TestClustersException

Unknown keys in user definition {} for {}

Error message

Unknown keys in user definition {} for {}

What it means

Thrown by user(userSpec) when the supplied map contains keys other than 'username', 'password', and 'role'. The node builds an elasticsearch-users useradd invocation from exactly those three keys; any extra key would be ignored silently, so the API rejects it to catch typos and schema drift.

Source

Thrown at build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java:743

        if (destination.contains("..")) {
            throw new IllegalArgumentException("extra config file destination can't be relative, was " + destination + " for " + this);
        }
        extraConfigFiles.put(destination, from, normalization);
    }

    @Override
    public void extraJarFiles(FileCollection from) {
        extraJarConfigurations.add(from);
    }

    @Override
    public void user(Map<String, String> userSpec) {
        Set<String> keys = new HashSet<>(userSpec.keySet());
        keys.remove("username");
        keys.remove("password");
        keys.remove("role");
        if (keys.isEmpty() == false) {
            throw new TestClustersException("Unknown keys in user definition " + keys + " for " + this);
        }
        Map<String, String> cred = new LinkedHashMap<>();
        cred.put("useradd", userSpec.getOrDefault("username", "test_user"));
        cred.put("-p", userSpec.getOrDefault("password", "x-pack-test-password"));
        cred.put("-r", userSpec.getOrDefault("role", "_es_test_root"));
        credentials.add(cred);
    }

    private File getBuildPluginFile(String name) {
        URL resource = getClass().getResource(name);
        return fileOperations.getResources().getText().fromUri(resource).asFile();
    }

    @Override
    public void rolesFile(File rolesYml) {
        roleFiles.add(rolesYml);
    }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Restrict the map to exactly username/password/role.
  2. Replace 'roles' with 'role', 'pass' with 'password', 'name'/'user' with 'username'.
  3. If you need multiple roles, pass them comma-separated as the single 'role' value (matches elasticsearch-users -r semantics).
  4. Filter the map before calling: userSpec.subMap(['username','password','role']).

Example fix

// before: wrong key names
user([user: 'alice', pass: 'secret', roles: 'superuser'])
// after: correct keys
user([username: 'alice', password: 'secret', role: 'superuser'])
Defensive patterns

Strategy: validation

Validate before calling

static final Set<String> USER_KEYS = Set.of("username", "password", "role");
static Map<String,String> sanitizeUser(Map<String,String> in) {
    Set<String> extra = new HashSet<>(in.keySet());
    extra.removeAll(USER_KEYS);
    if (!extra.isEmpty()) {
        throw new IllegalArgumentException("Unknown user keys " + extra + "; allowed " + USER_KEYS);
    }
    return in;
}
// Use: node.user(sanitizeUser(spec));

Type guard

static boolean isValidUserSpec(Map<String,String> in) {
    return USER_KEYS.containsAll(in.keySet());
}

Prevention

When it happens

Trigger: Calling node.user([username:'u', password:'p', role:'r', extra:'x']) with a stray key. Common culprits: 'roles' (plural) instead of 'role', 'pass' instead of 'password', 'name' instead of 'username', or test framework boilerplate passing through extra fields.

Common situations: Migrating from an older API that accepted 'roles' plural. Copy-paste from a REST example that uses different field names. Test fixture that forwards an unfiltered map.

Related errors


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