{"id":"f166f8a86436b240","repo":"apache/kafka","slug":"at-least-one-valid-string-must-be-provided-when-em","errorCode":null,"errorMessage":"At least one valid string must be provided when empty values are not allowed","messagePattern":"At least one valid string must be provided when empty values are not allowed","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/config/ConfigDef.java","lineNumber":1052,"sourceCode":"        final boolean isNullAllowed;\n\n        private ValidList(List<String> validStrings, boolean isEmptyAllowed, boolean isNullAllowed) {\n            this.validString = new ValidString(validStrings);\n            this.isEmptyAllowed = isEmptyAllowed;\n            this.isNullAllowed = isNullAllowed;\n        }\n\n        public static ValidList anyNonDuplicateValues(boolean isEmptyAllowed, boolean isNullAllowed) {\n            return new ValidList(List.of(), isEmptyAllowed, isNullAllowed);\n        }\n\n        public static ValidList in(String... validStrings) {\n            return new ValidList(List.of(validStrings), true, false);\n        }\n\n        public static ValidList in(boolean isEmptyAllowed, String... validStrings) {\n            if (!isEmptyAllowed && validStrings.length == 0) {\n                throw new IllegalArgumentException(\"At least one valid string must be provided when empty values are not allowed\");\n            }\n            return new ValidList(List.of(validStrings), isEmptyAllowed, false);\n        }\n\n        @Override\n        public void ensureValid(final String name, final Object value) {\n            if (value == null) {\n                if (isNullAllowed)\n                    return;\n                else\n                    throw new ConfigException(\"Configuration '\" + name + \"' values must not be null.\");\n            }\n\n            @SuppressWarnings(\"unchecked\")\n            List<Object> values = (List<Object>) value;\n            if (!isEmptyAllowed && values.isEmpty()) {\n                String validString = this.validString.validStrings.isEmpty() ? \"any non-empty value\" : this.validString.toString();\n                throw new ConfigException(\"Configuration '\" + name + \"' must not be empty. Valid values include: \" + validString);","sourceCodeStart":1034,"sourceCodeEnd":1070,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/config/ConfigDef.java#L1034-L1070","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass at least one allowed value: ValidList.in(false, \"a\",\"b\").","Or allow empty lists: ValidList.in(true).","If the allowed set is computed dynamically, guard the call: if (allowed.isEmpty()) ValidList.in(true) else ValidList.in(false, allowed.toArray).","Fail loudly at construction with a meaningful message rather than silently building an all-rejecting validator."],"exampleFix":"// before\nString[] allowed = discoverAllowedValues(); // returns empty\nValidator v = ConfigDef.ValidList.in(false, allowed);\n// -> IllegalArgumentException\n\n// after\nValidator v = allowed.length == 0\n    ? ConfigDef.ValidList.in(true)\n    : ConfigDef.ValidList.in(false, allowed);","handlingStrategy":"validation","validationCode":"if (!isEmptyAllowed && validStrings.length == 0) {\n    throw new IllegalArgumentException(\n        \"Supply at least one valid string, or set isEmptyAllowed=true\");\n}\nConfigDef.ValidList.in(isEmptyAllowed, validStrings);","typeGuard":"public static boolean isValidListArgs(boolean isEmptyAllowed, String[] validStrings) {\n    return isEmptyAllowed || (validStrings != null && validStrings.length > 0);\n}","tryCatchPattern":"try {\n    ConfigDef.ValidList.in(isEmptyAllowed, validStrings);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().equals(\"At least one valid string must be provided when empty values are not allowed\")) {\n        // either pass at least one allowed string, or set isEmptyAllowed=true\n    } else throw e;\n}","preventionTips":["When building a ValidList with isEmptyAllowed=false, always supply a non-empty allow-list.","Treat an empty allow-list combined with isEmptyAllowed=false as a programmer error, not a runtime condition.","Add a unit test that asserts your config builder calls never produce this combination."],"tags":["config","validation","connect","api-misuse","developer-error"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}