{"record":{"id":"81af389c0e0b04af","repo":"apache/kafka","slug":"the-upgradetype-flag-should-be-set-to-safe-downgra","errorCode":null,"errorMessage":"The upgradeType flag should be set to SAFE_DOWNGRADE or UNSAFE_DOWNGRADE when the provided maxVersionLevel:%d is < 1.","messagePattern":"The upgradeType flag should be set to SAFE_DOWNGRADE or UNSAFE_DOWNGRADE when the provided maxVersionLevel:(.+?) is < 1\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/admin/FeatureUpdate.java","lineNumber":73,"sourceCode":"            } else {\n                return UNKNOWN;\n            }\n        }\n    }\n\n    /**\n     * @param maxVersionLevel   The new maximum version level for the finalized feature.\n     *                          a value of zero is special and indicates that the update is intended to\n     *                          delete the finalized feature, and should be accompanied by setting\n     *                          the upgradeType to safe or unsafe.\n     * @param upgradeType     Indicate what kind of upgrade should be performed in this operation.\n     *                          - UPGRADE: upgrading the feature level\n     *                          - SAFE_DOWNGRADE: only downgrades which do not result in metadata loss are permitted\n     *                          - UNSAFE_DOWNGRADE: any downgrade, including those which may result in metadata loss, are permitted\n     */\n    public FeatureUpdate(final short maxVersionLevel, final UpgradeType upgradeType) {\n        if (maxVersionLevel == 0 && upgradeType.equals(UpgradeType.UPGRADE)) {\n            throw new IllegalArgumentException(String.format(\n                    \"The upgradeType flag should be set to SAFE_DOWNGRADE or UNSAFE_DOWNGRADE when the provided maxVersionLevel:%d is < 1.\",\n                    maxVersionLevel));\n        }\n        if (maxVersionLevel < 0) {\n            throw new IllegalArgumentException(\"Cannot specify a negative version level.\");\n        }\n        this.maxVersionLevel = maxVersionLevel;\n        this.upgradeType = upgradeType;\n    }\n\n    public short maxVersionLevel() {\n        return maxVersionLevel;\n    }\n\n    public UpgradeType upgradeType() {\n        return upgradeType;\n    }\n","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/apache/kafka/blob/996fb4585aa1bcc8980b0e1b8d6b168b986cd979/clients/src/main/java/org/apache/kafka/clients/admin/FeatureUpdate.java#L55-L91","documentation":"Thrown by the FeatureUpdate constructor when maxVersionLevel is 0 (the special 'delete this finalized feature' sentinel) but upgradeType is still UPGRADE. Deletion is a downgrade operation, so the client rejects the contradictory combination before it ever reaches the broker. The 0 level has no meaning as an upgrade target.","triggerScenarios":"Constructing new FeatureUpdate((short) 0, FeatureUpdate.UpgradeType.UPGRADE), or building a FeatureUpdate from deserialized/user input where the upgradeType defaulted to UPGRADE while the requested level was 0. Calling AdminClient.describeFeatures/alterFeatures machinery that builds a FeatureUpdate with level 0 and UPGRADE.","commonSituations":"Automation that deletes a finalized feature by setting its level to 0 but forgets to switch the upgrade type; copy-pasting an upgrade code path to perform a deletion; UI/config tooling that lets a user pick level 0 with an 'upgrade' intent.","solutions":["If your intent is to delete the finalized feature, pass UpgradeType.SAFE_DOWNGRADE or UpgradeType.UNSAFE_DOWNGRADE with maxVersionLevel 0.","If your intent is to upgrade, set maxVersionLevel to a positive value (>= 1) representing the target level.","Centralize FeatureUpdate construction behind a helper that derives upgradeType from the level so 0 always maps to a downgrade type."],"exampleFix":"// before\nnew FeatureUpdate((short) 0, FeatureUpdate.UpgradeType.UPGRADE);\n\n// after (delete the feature)\nnew FeatureUpdate((short) 0, FeatureUpdate.UpgradeType.SAFE_DOWNGRADE);","handlingStrategy":"validation","validationCode":"short level = ...;\nFeatureUpdate.UpgradeType type = (level == 0)\n    ? FeatureUpdate.UpgradeType.SAFE_DOWNGRADE\n    : FeatureUpdate.UpgradeType.UPGRADE;\n// safe to construct:\nnew FeatureUpdate(level, type);","typeGuard":"static boolean isLegalFeatureUpdateArgs(short level, FeatureUpdate.UpgradeType type) {\n    if (level < 0) return false;\n    if (level == 0 && type == FeatureUpdate.UpgradeType.UPGRADE) return false;\n    return true;\n}","tryCatchPattern":"try {\n    new FeatureUpdate(level, upgradeType);\n} catch (IllegalArgumentException e) {\n    // derive a safe upgradeType from level and retry, or surface to caller\n}","preventionTips":["Never pair level 0 with UPGRADE; treat 0 as 'delete' and pair it with a downgrade type.","Encapsulate FeatureUpdate construction in a single factory method that derives the upgrade type from the level."],"tags":["kafka-admin","feature-versioning","argument-validation","client-side"],"backgroundTag":null,"analyzedSha":"996fb4585aa1bcc8980b0e1b8d6b168b986cd979","analyzedAt":"2026-08-11T22:03:28.655Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}