{"record":{"id":"0317de1af2e96b36","repo":"apache/dubbo","slug":"delta-delta-0","errorCode":null,"errorMessage":"delta {delta} < 0","messagePattern":"delta (.+?) < 0","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/utils/AtomicPositiveInteger.java","lineNumber":73,"sourceCode":"    }\n\n    public final void set(int newValue) {\n        if (newValue < 0) {\n            throw new IllegalArgumentException(\"new value \" + newValue + \" < 0\");\n        }\n        INDEX_UPDATER.set(this, newValue);\n    }\n\n    public final int getAndSet(int newValue) {\n        if (newValue < 0) {\n            throw new IllegalArgumentException(\"new value \" + newValue + \" < 0\");\n        }\n        return INDEX_UPDATER.getAndSet(this, newValue) & Integer.MAX_VALUE;\n    }\n\n    public final int getAndAdd(int delta) {\n        if (delta < 0) {\n            throw new IllegalArgumentException(\"delta \" + delta + \" < 0\");\n        }\n        return INDEX_UPDATER.getAndAdd(this, delta) & Integer.MAX_VALUE;\n    }\n\n    public final int addAndGet(int delta) {\n        if (delta < 0) {\n            throw new IllegalArgumentException(\"delta \" + delta + \" < 0\");\n        }\n        return INDEX_UPDATER.addAndGet(this, delta) & Integer.MAX_VALUE;\n    }\n\n    public final boolean compareAndSet(int expect, int update) {\n        if (update < 0) {\n            throw new IllegalArgumentException(\"update value \" + update + \" < 0\");\n        }\n        return INDEX_UPDATER.compareAndSet(this, expect, update);\n    }\n","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AtomicPositiveInteger.java#L55-L91","documentation":"Thrown by AtomicPositiveInteger.getAndAdd when delta is negative. getAndAdd atomically adds delta and returns the prior value; a negative delta could drive the underlying field negative, breaking the non-negative masking guarantee, so it is rejected outright. Note that unlike AtomicInteger, this class forbids subtraction entirely.","triggerScenarios":"AtomicPositiveInteger.getAndAdd(delta) where delta < 0. Any code path that attempts to decrement via getAndAdd (rather than decrementAndGet, which masks the result) hits this guard.","commonSituations":"Porting code from AtomicInteger that used getAndAdd(-1) for decrementing; using a computed delta whose sign is wrong; generic algorithms that pass deltas that can go negative. This indicates the caller assumed AtomicInteger semantics.","solutions":["Use decrementAndGet() or getAndDecrement() for subtraction — these mask the result to stay non-negative.","If the delta is genuinely variable, split: if delta >= 0 use getAndAdd(delta), else call getAndDecrement() |delta| times or reconsider the data structure.","Switch to AtomicInteger if negative values are legitimately needed."],"exampleFix":"// before\napi.getAndAdd(-1); // throws\n\n// after\napi.getAndDecrement(); // non-negative masking built in","handlingStrategy":"validation","validationCode":"int delta = /* ... */;\nif (delta < 0) {\n    throw new IllegalArgumentException(\"getAndAdd needs delta >= 0; use getAndDecrement to subtract\");\n}\nint prev = api.getAndAdd(delta);","typeGuard":"static boolean isNonNegativeDelta(int d) { return d >= 0; }","tryCatchPattern":null,"preventionTips":["Use getAndDecrement() / decrementAndGet() for subtraction — they mask to non-negative.","Never port AtomicInteger.getAndAdd(-n) directly; switch to the decrement methods.","If variable deltas are needed, branch on sign before calling."],"tags":["atomic","invariant","load-balancer","numeric"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}