apache/dubbo · error · IllegalArgumentException

new value {newValue} < 0

Error message

new value {newValue} < 0

What it means

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.

Source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/utils/AtomicPositiveInteger.java:59

    public final int getAndDecrement() {
        return INDEX_UPDATER.getAndDecrement(this) & Integer.MAX_VALUE;
    }

    public final int incrementAndGet() {
        return INDEX_UPDATER.incrementAndGet(this) & Integer.MAX_VALUE;
    }

    public final int decrementAndGet() {
        return INDEX_UPDATER.decrementAndGet(this) & Integer.MAX_VALUE;
    }

    public final int get() {
        return INDEX_UPDATER.get(this) & Integer.MAX_VALUE;
    }

    public final void set(int newValue) {
        if (newValue < 0) {
            throw new IllegalArgumentException("new value " + newValue + " < 0");
        }
        INDEX_UPDATER.set(this, newValue);
    }

    public final int getAndSet(int newValue) {
        if (newValue < 0) {
            throw new IllegalArgumentException("new value " + newValue + " < 0");
        }
        return INDEX_UPDATER.getAndSet(this, newValue) & Integer.MAX_VALUE;
    }

    public final int getAndAdd(int delta) {
        if (delta < 0) {
            throw new IllegalArgumentException("delta " + delta + " < 0");
        }
        return INDEX_UPDATER.getAndAdd(this, delta) & Integer.MAX_VALUE;
    }

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Check the value is >= 0 before calling set(); if it can be negative by design, clamp or mask with (v & Integer.MAX_VALUE).
  2. Trace the caller computing newValue — usually an off-by-one or unsigned-math bug.
  3. Use getAndSet only after the same non-negative validation if you also need the previous value.

Example fix

// before
api.set(computedIndex); // computedIndex may be -1

// after
if (computedIndex < 0) computedIndex = 0;
api.set(computedIndex);
Defensive patterns

Strategy: validation

Validate before calling

int newValue = /* ... */;
if (newValue < 0) newValue = 0;
api.set(newValue);

Type guard

static boolean isNonNegative(int v) { return v >= 0; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14). Data as JSON: /api/errors/4c9b2dc4e2c77466. Report an issue: GitHub.