{"record":{"id":"4c9b2dc4e2c77466","repo":"apache/dubbo","slug":"new-value-newvalue-0","errorCode":null,"errorMessage":"new value {newValue} < 0","messagePattern":"new value (.+?) < 0","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/utils/AtomicPositiveInteger.java","lineNumber":59,"sourceCode":"    public final int getAndDecrement() {\n        return INDEX_UPDATER.getAndDecrement(this) & Integer.MAX_VALUE;\n    }\n\n    public final int incrementAndGet() {\n        return INDEX_UPDATER.incrementAndGet(this) & Integer.MAX_VALUE;\n    }\n\n    public final int decrementAndGet() {\n        return INDEX_UPDATER.decrementAndGet(this) & Integer.MAX_VALUE;\n    }\n\n    public final int get() {\n        return INDEX_UPDATER.get(this) & Integer.MAX_VALUE;\n    }\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","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AtomicPositiveInteger.java#L41-L77","documentation":"Thrown by AtomicPositiveInteger.set when the new value is negative. AtomicPositiveInteger is a Number whose value space is restricted to non-negative integers (it masks the underlying field with Integer.MAX_VALUE so getAndIncrement wraps without going negative). The set() mutator bypasses masking, so it explicitly rejects negative inputs to preserve the non-negative invariant.","triggerScenarios":"AtomicPositiveInteger.set(newValue) where newValue < 0. Used internally by Dubbo for round-robin / index selection in load balancers; any code path that resets the counter to a negative value triggers it.","commonSituations":"A load-balancer or selector that computes a starting index arithmetically and passes a negative result (overflow, bad modulo, wrong sign) to set(). Uncommon in normal operation; indicates a logic bug in the caller.","solutions":["Check the value is >= 0 before calling set(); if it can be negative by design, clamp or mask with (v & Integer.MAX_VALUE).","Trace the caller computing newValue — usually an off-by-one or unsigned-math bug.","Use getAndSet only after the same non-negative validation if you also need the previous value."],"exampleFix":"// before\napi.set(computedIndex); // computedIndex may be -1\n\n// after\nif (computedIndex < 0) computedIndex = 0;\napi.set(computedIndex);","handlingStrategy":"validation","validationCode":"int newValue = /* ... */;\nif (newValue < 0) newValue = 0;\napi.set(newValue);","typeGuard":"static boolean isNonNegative(int v) { return v >= 0; }","tryCatchPattern":null,"preventionTips":["Validate the value is >= 0 before calling set().","Audit index-arithmetic callers for sign errors.","If negatives are legitimate, use AtomicInteger instead."],"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"}