{"record":{"id":"0d0cec43ede4cea7","repo":"apache/cassandra","slug":"invalid-data-storage-value-must-be-non-negative","errorCode":null,"errorMessage":"Invalid data storage: value must be non-negative","messagePattern":"Invalid data storage: value must be non-negative","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/config/DataStorageSpec.java","lineNumber":110,"sourceCode":"    private static String acceptedUnits(DataStorageUnit minUnit)\n    {\n        DataStorageUnit[] units = DataStorageUnit.values();\n        return Arrays.toString(Arrays.copyOfRange(units, minUnit.ordinal(), units.length));\n    }\n\n    private static void validateQuantity(String value, long quantity, DataStorageUnit sourceUnit, DataStorageUnit minUnit, long max)\n    {\n        // no need to validate for negatives as they are not allowed at first place from the regex\n\n        if (minUnit.convert(quantity, sourceUnit) >= max)\n            throw new IllegalArgumentException(\"Invalid data storage: \" + value + \". It shouldn't be more than \" +\n                                               (max - 1) + \" in \" + toLowerCaseLocalized(minUnit.name()));\n    }\n\n    private static void validateQuantity(long quantity, DataStorageUnit sourceUnit, DataStorageUnit minUnit, long max)\n    {\n        if (quantity < 0)\n            throw new IllegalArgumentException(\"Invalid data storage: value must be non-negative\");\n\n        if (minUnit.convert(quantity, sourceUnit) >= max)\n            throw new IllegalArgumentException(String.format(\"Invalid data storage: %d %s. It shouldn't be more than %d in %s\",\n                                                             quantity, toLowerCaseLocalized(sourceUnit.name()),\n                                                             max - 1, toLowerCaseLocalized(minUnit.name())));\n    }\n\n    // get vs no-get prefix is not consistent in the code base, but for classes involved with config parsing, it is\n    // imporant to be explicit about get/set as this changes how parsing is done; this class is a data-type, so is\n    // not nested, having get/set can confuse parsing thinking this is a nested type\n    /**\n     * @return the data storage quantity.\n     */\n    public long quantity()\n    {\n        return quantity;\n    }\n","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/config/DataStorageSpec.java#L92-L128","documentation":"The programmatic (long-based) constructor of DataStorageSpec rejects negative quantities, since storage sizes cannot be negative. Unlike the string parser, which guards this via regex, the numeric constructor validates explicitly and throws IllegalArgumentException.","triggerScenarios":"Calling new DataStorageSpec.DataStorageBytesBound(-1024) (or any long-based DataStorageSpec constructor) with a negative value, typically from code that computes a size programmatically.","commonSituations":"Bugs in code that derives storage sizes from subtraction (e.g. remaining = total - used going negative), or uninitialized/default sentinel values like -1 being passed as a size.","solutions":["Fix the computation so the quantity is never negative","Clamp the value with Math.max(0, quantity) before constructing the spec","Check sentinel defaults (e.g. -1 meaning unset) and substitute a real value before passing it"],"exampleFix":"// before\nDataStorageSpec.DataStorageBytesBound bound = new DataStorageSpec.DataStorageBytesBound(freeBytes);\n// after\nif (freeBytes < 0) throw new IllegalStateException(\"computed negative size: \" + freeBytes);\nDataStorageSpec.DataStorageBytesBound bound = new DataStorageSpec.DataStorageBytesBound(Math.max(0, freeBytes));","handlingStrategy":"validation","validationCode":"if (quantity < 0) throw new IllegalArgumentException(\"size must be >= 0, got \" + quantity);","typeGuard":null,"tryCatchPattern":"try { new DataStorageSpec.DataStorageBytesBound(size); } catch (IllegalArgumentException e) { /* fall back to default */ }","preventionTips":["Check the source of computed sizes for subtraction underflow","Avoid -1 sentinels as sizes; use OptionalLong for unset","Clamp with Math.max(0, size) at construction sites"],"tags":["cassandra","config","data-storage-spec","negative-value"],"backgroundTag":"value-out-of-range","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}