{"id":"92ca9ad6ea79b083","repo":"apache/kafka","slug":"expected-minvalue-0-maxvalue-0-and-maxvalue","errorCode":null,"errorMessage":"Expected minValue >= 0, maxValue >= 0 and maxValue >= minValue, but received minValue: %d, maxValue: %d","messagePattern":"Expected minValue >= 0, maxValue >= 0 and maxValue >= minValue, but received minValue: (.+?), maxValue: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/feature/BaseVersionRange.java","lineNumber":64,"sourceCode":"    // The value of the maximum version.\n    private final short maxValue;\n\n    /**\n     * Raises an exception unless the following condition is met:\n     * minValue >= 0 and maxValue >= 0 and maxValue >= minValue.\n     *\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;","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/feature/BaseVersionRange.java#L46-L82","documentation":"Thrown as IllegalArgumentException by the BaseVersionRange constructor when the supplied minValue/maxValue pair violates the invariant minValue >= 0 AND maxValue >= 0 AND maxValue >= minValue. BaseVersionRange (and its subclasses like SupportedVersionRange / FinalizedVersionRange) model negotiated feature versions as non-negative shorts, so a negative value or an inverted range is treated as a programming error rather than a runtime condition. The message echoes both received values to make the violation obvious.","triggerScenarios":"Constructing a BaseVersionRange subclass with minValue<0, maxValue<0, or maxValue<minValue (e.g. new SupportedVersionRange((short)-1, (short)2) or new FinalizedVersionRange((short)5, (short)3)). Also reachable from fromMap() / feature-deserialization paths if a corrupted or hand-crafted metadata map feeds in inverted or negative values.","commonSituations":"Unit tests of feature negotiation passing sentinel values; a corrupted KRaft metadata record or a forged Features protobuf/map containing negative or inverted version fields; downstream tooling that synthesizes FinalizedVersionRange from user input without validating first.","solutions":["Inspect the printed minValue/maxValue pair: if minValue>maxValue, swap them; if either is negative, treat it as missing/unset rather than passing -1.","Validate at the boundary that converts external input (REST body, metadata record, CLI flag) into a version range, returning a 4xx / deserialization error instead of constructing the object.","In tests, use the factory methods (e.g. SupportedVersionRange.fromMap) which delegate to the same constructor, so feed them well-formed maps only.","If the values originate from KRaft metadata, dump the feature record and check whether a prior buggy writer produced the inverted values; recover from a known-good snapshot."],"exampleFix":"// before\nnew SupportedVersionRange((short) 5, (short) 3);\n\n// after\nnew SupportedVersionRange((short) 3, (short) 5);","handlingStrategy":"validation","validationCode":"short minValue = ..., maxValue = ...;\nif (minValue < 0 || maxValue < 0 || maxValue < minValue) {\n    throw new IllegalArgumentException(\n        \"Invalid version range: minValue=\" + minValue + \", maxValue=\" + maxValue);\n}\n// safe to construct the version range now","typeGuard":null,"tryCatchPattern":"try {\n    // construct a BaseVersionRange subclass (e.g. SupportedVersionRange)\n} catch (IllegalArgumentException e) {\n    // message starts with \"Expected minValue >= 0, maxValue >= 0 and maxValue >= minValue...\"\n    // reject the configuration / negotiated feature and continue with defaults\n}","preventionTips":["Treat version values as unsigned: coerce any parsed value to >= 0 before passing it in","When reading versions from config/protocol, validate maxValue >= minValue before constructing the range","Reject negative version values at the parsing boundary rather than at range construction","Unit-test range construction with (0,0), (min,max), and inverted pairs to catch regressions"],"tags":["feature-negotiation","version-range","validation","illegal-argument"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}