MyCATApache/Mycat-Server · error · IllegalArgumentException
Comparison method violates its general contract!
Error message
Comparison method violates its general contract!
What it means
TimSort.mergeLo throws IllegalArgumentException("Comparison method violates its general contract!") when a merge consumes all of run1's remaining elements (len1 reaches 0) in a way that indicates the comparator is inconsistent — typically one that violates the transitivity or antisymmetry contract of Comparator.compare. Java's (and this ported) TimSort detects the corruption defensively.
Solutions
- Fix the comparator to be a total order: sign-consistent, transitive, and stable during the sort.
- Never compare with subtraction on ints/longs; use Integer.compare/Long.compare to avoid overflow.
- Stop mutating the elements (or fields used by the comparator) while sorting; sort a snapshot.
- Ensure multi-field comparators fall back consistently, e.g. thenComparing chains with the same direction.
- As a temporary workaround, run with the legacy merge sort flag (useLegacyMergeSort) while fixing the comparator.
Example fix
// before (inconsistent, overflow-prone)
public int compare(Node a, Node b) { return (int)(a.score - b.score) ; }
// after
public int compare(Node a, Node b) { return Long.compare(a.score, b.score); } Defensive patterns
Strategy: validation
Validate before calling
// verify transitivity before sorting
static <T> boolean isConsistent(Comparator<T> c, List<T> sample) {
for (T a : sample) for (T b : sample) for (T d : sample)
if (c.compare(a,b) < 0 && c.compare(b,d) < 0 && c.compare(a,d) > 0) return false;
return true;
} Try / catch
try { Collections.sort(list, cmp); } catch (IllegalArgumentException e) { if (e.getMessage().contains("general contract")) { list.sort(Comparator.comparingLong(Key::of)); } else throw e; } Prevention
- Use Integer.compare/Long.compare instead of subtraction
- Never mutate elements while sorting
- Write transitivity unit tests for custom comparators
- Avoid comparator logic depending on random or time-varying state
When it happens
Trigger: Sorting with a comparator whose result is inconsistent across calls: it depends on mutable object state that changes during the sort, returns contradictory results (compare(a,b) and compare(b,a) both positive), or is not transitive.
Common situations: Comparators that call Math.random() or read fields mutated concurrently by another thread; multi-key comparators with inconsistent tie-breaking (e.g. comparing a-b on one key but b-a on another); double subtraction overflow (int)(a - b) for large values.
Related errors
- Not enough memory to grow pointer array
- There is no space for new record
- Number of records written exceeded numRecordsToWrite =
AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11).
Data as JSON: /api/errors/f024954184475f34.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/io/mycat/memory/unsafe/utils/sort/TimSort.java:792
break outer;
}
s.copyElement(tmp, cursor1++, a, dest++);
if (--len1 == 1)
break outer;
minGallop--;
} while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
if (minGallop < 0)
minGallop = 0;
minGallop += 2; // Penalize for leaving gallop mode
} // End of "outer" loop
this.minGallop = minGallop < 1 ? 1 : minGallop; // Write back to field
if (len1 == 1) {
assert len2 > 0;
s.copyRange(a, cursor2, a, dest, len2);
s.copyElement(tmp, cursor1, a, dest + len2); // Last elt of run 1 to end of merge
} else if (len1 == 0) {
throw new IllegalArgumentException(
"Comparison method violates its general contract!");
} else {
assert len2 == 0;
assert len1 > 1;
s.copyRange(tmp, cursor1, a, dest, len1);
}
}
/**
* Like mergeLo, except that this method should be called only if
* len1 >= len2; mergeLo should be called if len1 <= len2. (Either method
* may be called if len1 == len2.)
*
* @param base1 index of first element in first run to be merged
* @param len1 length of first run to be merged (must be > 0)
* @param base2 index of first element in second run to be merged
* (must be aBase + aLen)
* @param len2 length of second run to be merged (must be > 0)View on GitHub (pinned to 65f8d8beb7)