TheAlgorithms/Java · error · IllegalArgumentException
Cannot compare PN-Counters with different number of nodes
Error message
Cannot compare PN-Counters with different number of nodes
What it means
PNCounter.compare() requires both counters to have the same cluster size n, because it iterates element-wise over node indices [0, n). The PN-Counter CRDT model assumes a fixed, agreed-upon cluster topology; comparing counters from different-sized clusters is undefined and would cause IndexOutOfBoundsException on the underlying maps if not guarded.
Source
Thrown at src/main/java/com/thealgorithms/datastructures/crdt/PNCounter.java:76
* Gets the total value of the counter by subtracting the decrement counter from the increment counter.
*
* @return The total value of the counter.
*/
public int value() {
int sumP = pCounter.values().stream().mapToInt(Integer::intValue).sum();
int sumN = nCounter.values().stream().mapToInt(Integer::intValue).sum();
return sumP - sumN;
}
/**
* Compares the state of this PN-Counter with another PN-Counter.
*
* @param other The other PN-Counter to compare with.
* @return True if the state of this PN-Counter is less than or equal to the state of the other PN-Counter.
*/
public boolean compare(PNCounter other) {
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");
}View on GitHub (pinned to fdfb9a395b)
Solutions
- Ensure all PNCounter instances in a cluster are constructed with the same n value
- When scaling the cluster, recreate all counters with the new n before comparing or merging
- Check counter.n equality (or expose it) before calling compare()
Example fix
// before PNCounter a = new PNCounter(0, 3); PNCounter b = new PNCounter(0, 5); a.compare(b); // throws // after — agree on cluster size at construction time int clusterSize = ClusterConfig.getNodeCount(); PNCounter a = new PNCounter(0, clusterSize); PNCounter b = new PNCounter(0, clusterSize); a.compare(b);
Defensive patterns
Strategy: validation
Validate before calling
// Expose n or track it externally, then verify before compare.
// PNCounter.n is package-private; if accessible:
if (thisCounter.n != otherCounter.n) {
throw new IllegalStateException("Cluster size mismatch");
}
thisCounter.compare(otherCounter); Try / catch
try {
return a.compare(b);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("different number of nodes")) {
// topology mismatch — skip comparison or resync
return false;
}
throw e;
} Prevention
- Standardize the cluster size n across all nodes and replicas
- Recreate all PNCounter instances when the cluster topology changes
- Track and verify n before any cross-replica compare or merge
When it happens
Trigger: Calling counter1.compare(counter2) where counter1 was constructed as new PNCounter(id, 3) and counter2 as new PNCounter(id, 5). Also when counters are deserialized from different deployments or cluster generations.
Common situations: Dynamically scaling a cluster (adding new nodes) without recreating all counters with the new n. Mixing counters from different environments (staging vs. production). Counters received over the network from a peer with a different cluster configuration.
Related errors
- Cannot merge PN-Counters with different number of nodes
- Input cannot be negative
- The exponent must be positive
- Input must be a non-empty binary string.
- Input must contain only '0' and '1'. Found: {}
AI-assisted analysis of TheAlgorithms/Java@fdfb9a395b (2026-08-13).
Data as JSON: /api/errors/339295ae1e8b7409.
Report an issue: GitHub.