apache/kafka · error · IllegalArgumentException

At least one valid string must be provided when empty values

Error message

At least one valid string must be provided when empty values are not allowed

What it means

Thrown by the ValidList.in(boolean isEmptyAllowed, String...) static factory when isEmptyAllowed is false but no validStrings were supplied. ValidList is a Validator that restricts a LIST-typed config to a fixed set of allowed values; disallowing empty lists while providing no allowed values is contradictory (every list would be invalid), so the factory refuses to build the Validator. This is a developer/config-author error in ConfigDef construction, not a runtime config-value error.

Source

Thrown at clients/src/main/java/org/apache/kafka/common/config/ConfigDef.java:1052

        final boolean isNullAllowed;

        private ValidList(List<String> validStrings, boolean isEmptyAllowed, boolean isNullAllowed) {
            this.validString = new ValidString(validStrings);
            this.isEmptyAllowed = isEmptyAllowed;
            this.isNullAllowed = isNullAllowed;
        }

        public static ValidList anyNonDuplicateValues(boolean isEmptyAllowed, boolean isNullAllowed) {
            return new ValidList(List.of(), isEmptyAllowed, isNullAllowed);
        }

        public static ValidList in(String... validStrings) {
            return new ValidList(List.of(validStrings), true, false);
        }

        public static ValidList in(boolean isEmptyAllowed, String... validStrings) {
            if (!isEmptyAllowed && validStrings.length == 0) {
                throw new IllegalArgumentException("At least one valid string must be provided when empty values are not allowed");
            }
            return new ValidList(List.of(validStrings), isEmptyAllowed, false);
        }

        @Override
        public void ensureValid(final String name, final Object value) {
            if (value == null) {
                if (isNullAllowed)
                    return;
                else
                    throw new ConfigException("Configuration '" + name + "' values must not be null.");
            }

            @SuppressWarnings("unchecked")
            List<Object> values = (List<Object>) value;
            if (!isEmptyAllowed && values.isEmpty()) {
                String validString = this.validString.validStrings.isEmpty() ? "any non-empty value" : this.validString.toString();
                throw new ConfigException("Configuration '" + name + "' must not be empty. Valid values include: " + validString);

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Pass at least one allowed value: ValidList.in(false, "a","b").
  2. Or allow empty lists: ValidList.in(true).
  3. If the allowed set is computed dynamically, guard the call: if (allowed.isEmpty()) ValidList.in(true) else ValidList.in(false, allowed.toArray).
  4. Fail loudly at construction with a meaningful message rather than silently building an all-rejecting validator.

Example fix

// before
String[] allowed = discoverAllowedValues(); // returns empty
Validator v = ConfigDef.ValidList.in(false, allowed);
// -> IllegalArgumentException

// after
Validator v = allowed.length == 0
    ? ConfigDef.ValidList.in(true)
    : ConfigDef.ValidList.in(false, allowed);
Defensive patterns

Strategy: validation

Validate before calling

if (!isEmptyAllowed && validStrings.length == 0) {
    throw new IllegalArgumentException(
        "Supply at least one valid string, or set isEmptyAllowed=true");
}
ConfigDef.ValidList.in(isEmptyAllowed, validStrings);

Type guard

public static boolean isValidListArgs(boolean isEmptyAllowed, String[] validStrings) {
    return isEmptyAllowed || (validStrings != null && validStrings.length > 0);
}

Try / catch

try {
    ConfigDef.ValidList.in(isEmptyAllowed, validStrings);
} catch (IllegalArgumentException e) {
    if (e.getMessage().equals("At least one valid string must be provided when empty values are not allowed")) {
        // either pass at least one allowed string, or set isEmptyAllowed=true
    } else throw e;
}

Prevention

When it happens

Trigger: Calling ConfigDef.ValidList.in(false) or ConfigDef.ValidList.in(false, new String[0]) when building a custom ConfigDef — typically a custom Kafka Connect connector, a custom Streams config, or a broker plugin that defines its own enum-like LIST config. The factory throws IllegalArgumentException at ConfigDef build time, before any client is started.

Common situations: Custom connector author wires ValidList.in(false, allowedArray) where allowedArray is computed at runtime (e.g. from config or service discovery) and ends up empty; refactoring that moves the allowed-values list into a separate method that returns empty under some condition; copy-paste of a ValidString.in pattern into ValidList without supplying values; conditional config that builds the validator only when a feature flag is off.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/f166f8a86436b240.json. Report an issue: GitHub.