{"record":{"id":"cc3f9b8604f868dd","repo":"apache/dubbo","slug":"update-value-update-0","errorCode":null,"errorMessage":"update value {update} < 0","messagePattern":"update value (.+?) < 0","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/utils/AtomicPositiveInteger.java","lineNumber":87,"sourceCode":"    }\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\n    public final boolean weakCompareAndSet(int expect, int update) {\n        if (update < 0) {\n            throw new IllegalArgumentException(\"update value \" + update + \" < 0\");\n        }\n        return INDEX_UPDATER.weakCompareAndSet(this, expect, update);\n    }\n\n    @Override\n    public byte byteValue() {\n        return (byte) get();\n    }\n\n    @Override\n    public short shortValue() {","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AtomicPositiveInteger.java#L69-L105","documentation":"Thrown by AtomicPositiveInteger.compareAndSet when the update value is negative. CAS atomically swaps to 'update' only if the current value equals 'expect'; since 'update' must remain non-negative per the class invariant, a negative update is rejected before the CAS is attempted.","triggerScenarios":"AtomicPositiveInteger.compareAndSet(expect, update) where update < 0. The 'expect' value is not constrained (it may not match), but 'update' must be non-negative.","commonSituations":"Lock-free algorithm ported from AtomicInteger where the desired new state can be negative; a computed 'update' with a sign error; off-by-one in a CAS loop. Indicates the caller's algorithm is incompatible with the non-negative contract.","solutions":["Ensure the computed 'update' is always >= 0; mask with (v & Integer.MAX_VALUE) if wraparound is acceptable.","Rethink the algorithm: AtomicPositiveInteger is designed for round-robin indices that only ever grow/wrap, not arbitrary state machines.","Switch to AtomicInteger if the value legitimately needs to be negative."],"exampleFix":"// before\napi.compareAndSet(old, next); // next may be negative\n\n// after\napi.compareAndSet(old, next < 0 ? 0 : next);","handlingStrategy":"validation","validationCode":"int update = /* ... */;\nif (update < 0) update = 0; // or (update & Integer.MAX_VALUE)\napi.compareAndSet(expect, update);","typeGuard":"static boolean isNonNegative(int v) { return v >= 0; }","tryCatchPattern":null,"preventionTips":["Ensure the CAS 'update' target is non-negative; mask if wraparound is acceptable.","Reconsider the algorithm if it needs negative states — AtomicPositiveInteger only models growing/wrapping indices.","Use AtomicInteger for arbitrary signed state machines."],"tags":["atomic","invariant","cas","numeric"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}