google/guava · error · AssertionFailedError

$ITEM must not be $RELATIONSHIP to $OTHER

Error message

$ITEM must not be $RELATIONSHIP to $OTHER

What it means

RelationshipTester (used by EqualsTester) requires that items placed in different equality groups are NOT equivalent. assertUnrelated() checks equivalence.equivalent(item, unrelated) and throws AssertionFailedError when two cross-group items test as equal — this is a direct violation of the equals/hashCode contract as expressed by the declared grouping.

Source

Thrown at android/guava-testlib/src/com/google/common/testing/RelationshipTester.java:141

        relatedInfo,
        itemHash == relatedHash);
  }

  private void assertUnrelated(
      int groupNumber, int itemNumber, int unrelatedGroupNumber, int unrelatedItemNumber) {
    Item<T> itemInfo = getItem(groupNumber, itemNumber);
    Item<T> unrelatedInfo = getItem(unrelatedGroupNumber, unrelatedItemNumber);

    assertWithTemplate(
        "$ITEM must not be $RELATIONSHIP to $OTHER",
        itemInfo,
        unrelatedInfo,
        !equivalence.equivalent(itemInfo.value, unrelatedInfo.value));
  }

  private void assertWithTemplate(String template, Item<T> item, Item<T> other, boolean condition) {
    if (!condition) {
      throw new AssertionFailedError(
          template
              .replace("$RELATIONSHIP", relationshipName)
              .replace("$HASH", hashName)
              .replace("$ITEM", itemReporter.reportItem(item))
              .replace("$OTHER", itemReporter.reportItem(other)));
    }
  }

  private Item<T> getItem(int groupNumber, int itemNumber) {
    return new Item<>(groups.get(groupNumber).get(itemNumber), groupNumber, itemNumber);
  }

  static final class Item<T> {
    final T value;
    final int groupNumber;
    final int itemNumber;

    Item(T value, int groupNumber, int itemNumber) {

View on GitHub (pinned to 94f39958ba)

Solutions

  1. Fix equals()/hashCode() so objects differing in the relevant fields return false.
  2. Move genuinely-equal objects into the same equality group (the whole point of groups is to separate unequal clusters).
  3. Ensure objects in different groups differ in at least one field that equals() consults.
  4. If using a custom Equivalence, confirm it reflects the intended distinctness.

Example fix

// before
@Override public boolean equals(Object o) {
  return o instanceof Key; // ignores id -> cross-group items match
}

// after
@Override public boolean equals(Object o) {
  return o instanceof Key && ((Key) o).id == this.id;
}
Defensive patterns

Strategy: validation

Validate before calling

// Sanity-check your grouping by hand before handing it to EqualsTester:
// all items within a group must be equal; items in different groups must differ.
for (Object a : groupX) for (Object b : groupY) {
  if (a.equals(b)) throw new IllegalStateException("cross-group equality: " + a);
}

Prevention

When it happens

Trigger: new EqualsTester().addEqualityGroup(a1).addEqualityGroup(b1).testEquals() where a1.equals(b1) returns true (or an Equivalence wrapped via RelationshipTester reports them equivalent). The tester treats groups as mutually unrelated.

Common situations: equals() compares too few fields (so distinct objects compare equal); using only hashCode for equality; objects in different groups that happen to represent the same logical value; grouping mistakes where equal objects were put in separate groups.

Related errors


AI-assisted analysis of google/guava@94f39958ba (2026-08-13). Data as JSON: /api/errors/a1075e9889befd22. Report an issue: GitHub.