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
- Fix equals()/hashCode() so objects differing in the relevant fields return false.
- Move genuinely-equal objects into the same equality group (the whole point of groups is to separate unequal clusters).
- Ensure objects in different groups differ in at least one field that equals() consults.
- 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
- Ensure equals()/hashCode() use all fields that define logical identity.
- Place genuinely equal objects in the same group; use new groups only for distinct clusters.
- Never implement equals() on hashCode() alone.
- When using a custom Equivalence, verify it agrees with the grouping.
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
- at index %s
- wrong exception thrown from %s when passing null to %s param
- %s returns null and cannot be used to test instance methods.
- Unexpected interrupt while waiting for future
- Unexpected interrupt while waiting for latch
AI-assisted analysis of google/guava@94f39958ba (2026-08-13).
Data as JSON: /api/errors/a1075e9889befd22.
Report an issue: GitHub.