{"id":"16286b522f468e08","repo":"apache/kafka","slug":"expected-minkeylabel-to-be-non-empty","errorCode":null,"errorMessage":"Expected minKeyLabel to be non-empty.","messagePattern":"Expected minKeyLabel to be non-empty\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/feature/BaseVersionRange.java","lineNumber":70,"sourceCode":"     *\n     * @param minKeyLabel   Label for the min version key, that's used only to convert to/from a map.\n     * @param minValue      The minimum version value.\n     * @param maxKeyLabel   Label for the max version key, that's used only to convert to/from a map.\n     * @param maxValue      The maximum version value.\n     *\n     * @throws IllegalArgumentException   If any of the following conditions are true:\n     *                                     - (minValue < 0) OR (maxValue < 0) OR (maxValue < minValue).\n     *                                     - minKeyLabel is empty, OR, minKeyLabel is empty.\n     */\n    protected BaseVersionRange(String minKeyLabel, short minValue, String maxKeyLabel, short maxValue) {\n        if (minValue < 0 || maxValue < 0 || maxValue < minValue) {\n            throw new IllegalArgumentException(\n                String.format(\n                    \"Expected minValue >= 0, maxValue >= 0 and maxValue >= minValue, but received\" +\n                    \" minValue: %d, maxValue: %d\", minValue, maxValue));\n        }\n        if (minKeyLabel.isEmpty()) {\n            throw new IllegalArgumentException(\"Expected minKeyLabel to be non-empty.\");\n        }\n        if (maxKeyLabel.isEmpty()) {\n            throw new IllegalArgumentException(\"Expected maxKeyLabel to be non-empty.\");\n        }\n        this.minKeyLabel = minKeyLabel;\n        this.minValue = minValue;\n        this.maxKeyLabel = maxKeyLabel;\n        this.maxValue = maxValue;\n    }\n\n    public short min() {\n        return minValue;\n    }\n\n    public short max() {\n        return maxValue;\n    }\n","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/feature/BaseVersionRange.java#L52-L88","documentation":"Thrown as IllegalArgumentException by the BaseVersionRange constructor when minKeyLabel is the empty string. The min/max key labels are the map keys used when serializing the range to/from a Map (e.g. 'min_version' / 'max_version'); an empty label would produce an ambiguous, unparseable map, so the constructor rejects it eagerly. Subclasses supply these labels, so the error is almost always a subclass-implementation bug, not end-user input.","triggerScenarios":"A subclass of BaseVersionRange passes \"\" as minKeyLabel to super(...); invoking fromMap() on a map whose structure was tampered with cannot itself trigger this (fromMap uses valueOrThrow, not the empty-label check), so the trigger is always direct construction with a bad label constant.","commonSituations":"Introducing a new BaseVersionRange subclass and forgetting to initialize the label constant; a refactor that replaces a constant with a field that is null-or-empty at super() call time; copy-paste errors where min and max labels are swapped or one is dropped.","solutions":["Check the subclass: confirm the minKeyLabel passed to super(...) is a non-empty literal/constant (e.g. \"min_version\").","If the label is derived from configuration or input, validate non-empty before invoking the constructor and fail with a domain-specific error instead.","Add a unit test that constructs the subclass with its default labels to lock in the invariant."],"exampleFix":"// before\nclass MyVersionRange extends BaseVersionRange {\n    MyVersionRange(short min, short max) {\n        super(\"\", min, \"max_version\", max);\n    }\n}\n\n// after\nclass MyVersionRange extends BaseVersionRange {\n    MyVersionRange(short min, short max) {\n        super(\"min_version\", min, \"max_version\", max);\n    }\n}","handlingStrategy":"validation","validationCode":"String minKeyLabel = ...;\nif (minKeyLabel == null || minKeyLabel.isEmpty()) {\n    throw new IllegalArgumentException(\"minKeyLabel must be non-empty\");\n}\n// safe to proceed","typeGuard":"static boolean isValidKeyLabel(String label) {\n    return label != null && !label.isEmpty();\n}","tryCatchPattern":"try {\n    // construct the version range with minKeyLabel\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"minKeyLabel\")) {\n        // supply a default label or fail configuration loading\n    } else { throw e; }\n}","preventionTips":["Do not derive minKeyLabel from external/user input without a non-empty check","Use constants for well-known labels (e.g. \"min_version\") instead of computed strings","Validate label strings at the configuration parsing boundary","Guard against accidental null-to-empty coercion (e.g. toString() on a null object) producing \"\""],"tags":["feature-negotiation","version-range","validation","illegal-argument"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}