Java "Comparison method violates its general contract!" - Fix Sort in CI
A sort threw IllegalArgumentException: Comparison method violates its general contract!. Java’s TimSort detected that your Comparator/compareTo is not a valid total order - it is not antisymmetric, transitive, or consistent - and aborts rather than producing a wrong order.
What this error means
A Collections.sort/list.sort/Stream.sorted call fails with Comparison method violates its general contract!. It can appear only on larger inputs (TimSort only checks the contract past a threshold), which makes it look intermittent - but the comparator is genuinely broken.
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.base/java.util.TimSort.mergeHi(TimSort.java:903)
at java.base/java.util.TimSort.mergeAt(TimSort.java:520)
at java.base/java.util.Arrays.sort(Arrays.java:1307)
at com.example.Ranker.rank(Ranker.java:48)Common causes
Non-transitive or inconsistent comparator
A comparator that returns results inconsistent with itself - e.g. subtracting fields with overflow, comparing with == on doubles, or branching that breaks compare(a,b) == -compare(b,a) - violates the total-order contract.
Integer overflow in subtraction-based compare
Returning a.value - b.value overflows for large/negative values, flipping the sign and breaking antisymmetry. It often works for small data and fails once TimSort actually checks.
How to fix it
Build the comparator from safe primitives
Use Comparator.comparing* / Integer.compare so the order is total and overflow-free.
// broken: overflow breaks antisymmetry
// list.sort((a, b) -> a.score - b.score);
// correct:
list.sort(Comparator.comparingInt(Item::score)
.thenComparing(Item::name));Ensure every field comparison is consistent
- Use
Integer.compare/Double.compare, never raw subtraction. - Make sure ties are broken consistently (chain
thenComparing). - Avoid comparisons that depend on mutable state changing during the sort.
How to prevent it
- Construct comparators with
Comparator.comparing*andInteger/Double.compare. - Never compare by subtraction (overflow) or by
==on floating point. - Test sorting on large, adversarial datasets so contract violations surface in CI.