{"record":{"id":"339295ae1e8b7409","repo":"TheAlgorithms/Java","slug":"cannot-compare-pn-counters-with-different-number-o","errorCode":null,"errorMessage":"Cannot compare PN-Counters with different number of nodes","messagePattern":"Cannot compare PN-Counters with different number of nodes","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/thealgorithms/datastructures/crdt/PNCounter.java","lineNumber":76,"sourceCode":"     * Gets the total value of the counter by subtracting the decrement counter from the increment counter.\n     *\n     * @return The total value of the counter.\n     */\n    public int value() {\n        int sumP = pCounter.values().stream().mapToInt(Integer::intValue).sum();\n        int sumN = nCounter.values().stream().mapToInt(Integer::intValue).sum();\n        return sumP - sumN;\n    }\n\n    /**\n     * Compares the state of this PN-Counter with another PN-Counter.\n     *\n     * @param other The other PN-Counter to compare with.\n     * @return True if the state of this PN-Counter is less than or equal to the state of the other PN-Counter.\n     */\n    public boolean compare(PNCounter other) {\n        if (this.n != other.n) {\n            throw new IllegalArgumentException(\"Cannot compare PN-Counters with different number of nodes\");\n        }\n        for (int i = 0; i < n; i++) {\n            if (this.pCounter.get(i) > other.pCounter.get(i) && this.nCounter.get(i) > other.nCounter.get(i)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Merges the state of this PN-Counter with another PN-Counter.\n     *\n     * @param other The other PN-Counter to merge with.\n     */\n    public void merge(PNCounter other) {\n        if (this.n != other.n) {\n            throw new IllegalArgumentException(\"Cannot merge PN-Counters with different number of nodes\");\n        }","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/TheAlgorithms/Java/blob/fdfb9a395b310167a66bd29e311e36e0e3e9b964/src/main/java/com/thealgorithms/datastructures/crdt/PNCounter.java#L58-L94","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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()"],"exampleFix":"// before\nPNCounter a = new PNCounter(0, 3);\nPNCounter b = new PNCounter(0, 5);\na.compare(b); // throws\n\n// after — agree on cluster size at construction time\nint clusterSize = ClusterConfig.getNodeCount();\nPNCounter a = new PNCounter(0, clusterSize);\nPNCounter b = new PNCounter(0, clusterSize);\na.compare(b);","handlingStrategy":"validation","validationCode":"// Expose n or track it externally, then verify before compare.\n// PNCounter.n is package-private; if accessible:\nif (thisCounter.n != otherCounter.n) {\n    throw new IllegalStateException(\"Cluster size mismatch\");\n}\nthisCounter.compare(otherCounter);","typeGuard":null,"tryCatchPattern":"try {\n    return a.compare(b);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"different number of nodes\")) {\n        // topology mismatch — skip comparison or resync\n        return false;\n    }\n    throw e;\n}","preventionTips":["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"],"tags":["crdt","pncounter","distributed-systems","validation"],"backgroundTag":null,"analyzedSha":"fdfb9a395b310167a66bd29e311e36e0e3e9b964","analyzedAt":"2026-08-13T23:36:13.315Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}