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

  1. Fix the comparator to be a total order: sign-consistent, transitive, and stable during the sort.
  2. Never compare with subtraction on ints/longs; use Integer.compare/Long.compare to avoid overflow.
  3. Stop mutating the elements (or fields used by the comparator) while sorting; sort a snapshot.
  4. Ensure multi-field comparators fall back consistently, e.g. thenComparing chains with the same direction.
  5. 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

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


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)