TheAlgorithms/Java · error · IllegalArgumentException

Cannot merge PN-Counters with different number of nodes

Error message

Cannot merge PN-Counters with different number of nodes

What it means

PNCounter.merge() requires both counters to share the same cluster size n. Merge computes the element-wise maximum across all node indices [0, n); differing n values would leave some indices unmerged or cause map access errors. The CRDT merge operation is only defined for counters from the same cluster topology.

Source

Thrown at src/main/java/com/thealgorithms/datastructures/crdt/PNCounter.java:93

        if (this.n != other.n) {
            throw new IllegalArgumentException("Cannot compare PN-Counters with different number of nodes");
        }
        for (int i = 0; i < n; i++) {
            if (this.pCounter.get(i) > other.pCounter.get(i) && this.nCounter.get(i) > other.nCounter.get(i)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Merges the state of this PN-Counter with another PN-Counter.
     *
     * @param other The other PN-Counter to merge with.
     */
    public void merge(PNCounter other) {
        if (this.n != other.n) {
            throw new IllegalArgumentException("Cannot merge PN-Counters with different number of nodes");
        }
        for (int i = 0; i < n; i++) {
            this.pCounter.put(i, Math.max(this.pCounter.get(i), other.pCounter.get(i)));
            this.nCounter.put(i, Math.max(this.nCounter.get(i), other.nCounter.get(i)));
        }
    }
}

View on GitHub (pinned to fdfb9a395b)

Solutions

  1. Standardize n across all replicas before any merge operation
  2. Recreate all PNCounter instances with the updated cluster size when topology changes
  3. Validate n equality before calling merge() and handle mismatch gracefully

Example fix

// before
PNCounter local = new PNCounter(0, 3);
PNCounter remote = deserializeFromNetwork(); // n=5
local.merge(remote); // throws

// after — verify topology match before merge
if (local.getN() != remote.getN()) {
    throw new TopologyMismatchException("cluster sizes differ");
}
local.merge(remote);
Defensive patterns

Strategy: validation

Validate before calling

// Verify cluster sizes match before merging.
if (localCounter.n != remoteCounter.n) {
    throw new TopologyMismatchException("Cannot merge: cluster sizes differ");
}
localCounter.merge(remoteCounter);

Try / catch

try {
    local.merge(remote);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("different number of nodes")) {
        // handle topology mismatch: resync or skip
        logger.warn("Skipped merge due to topology mismatch");
    } else throw e;
}

Prevention

When it happens

Trigger: Calling counter1.merge(counter2) where the two counters were constructed with different n values (e.g., PNCounter(0, 3) and PNCounter(1, 5)).

Common situations: Cluster topology changed (nodes added/removed) and old counters were not recreated. Counters arriving from a remote replica with a different n. Mixing test fixtures with production counters that have different cluster sizes.

Related errors


AI-assisted analysis of TheAlgorithms/Java@fdfb9a395b (2026-08-13). Data as JSON: /api/errors/4e3884837a3e16e9. Report an issue: GitHub.