google/guava · error · AssertionFailedError
Should not call merge function if value was null
Error message
Should not call merge function if value was null
What it means
Thrown inside the remapping function of MapMergeTester.testMergeNullValue. Per Map.merge contract, if the new value is null the result must be removal of the key (or no-op if absent) and the remapping function MUST NOT be invoked. This firing means your Map incorrectly calls the function before/while handling a null new value.
Source
Thrown at android/guava-testlib/src/com/google/common/collect/testing/testers/MapMergeTester.java:161
(oldV, newV) -> {
assertEquals(v0(), oldV);
assertEquals(v3(), newV);
return null;
}));
expectMissing(e0());
}
public void testMergeNullValue() {
RuntimeException expected =
assertThrows(
RuntimeException.class,
() ->
getMap()
.merge(
k0(),
null,
(oldV, newV) -> {
throw new AssertionFailedError(
"Should not call merge function if value was null");
}));
if (!(expected instanceof NullPointerException
|| expected instanceof UnsupportedOperationException)) {
throw expected;
}
}
public void testMergeNullFunction() {
RuntimeException expected =
assertThrows(RuntimeException.class, () -> getMap().merge(k0(), v3(), null));
if (!(expected instanceof NullPointerException
|| expected instanceof UnsupportedOperationException)) {
throw expected;
}
}
@MapFeature.Require(absent = SUPPORTS_PUT)View on GitHub (pinned to 94f39958ba)
Solutions
- Validate the value parameter first: if value == null, throw NullPointerException (or UnsupportedOperationException if null values unsupported) WITHOUT calling the function.
- Match the contract: null value => remove the key (if present) and return null; never invoke the function for a null value.
- Ensure any exception thrown is NullPointerException or UnsupportedOperationException so the tester's expected-exception check passes.
Example fix
// before
V merged = f.apply(get(k), v); // BUG: called even when v == null
if (merged == null) remove(k); else put(k, merged);
// after
Objects.requireNonNull(v); // NPE before touching the function
V old = get(k);
if (old == null) { put(k, v); return v; }
V merged = f.apply(old, v);
if (merged == null) remove(k); else put(k, merged);
return merged; Defensive patterns
Strategy: validation
Validate before calling
RuntimeException ex = assertThrows(RuntimeException.class, () -> m.merge(k0(), null, throwingFn)); if (!(ex instanceof NullPointerException || ex instanceof UnsupportedOperationException)) throw ex;
Prevention
- Null-check the value parameter at the top of merge() before invoking the function.
- Throw only NullPointerException (or UnsupportedOperationException) for null values/unsupported.
When it happens
Trigger: testMergeNullValue passes a null value to merge and a function that throws AssertionFailedError; the wrapped exception must be NullPointerException or UnsupportedOperationException. If your Map calls the function (rethrowing the assertion) or throws something else, the test rethrows it.
Common situations: A merge() that computes merged = f.apply(old, newV) unconditionally before checking whether newV is null; implementations that throw IllegalArgumentException or a custom exception for null values instead of NPE/UnsupportedOperationException.
Related errors
- Should not call merge function if key was mapped to null
- Should not call merge function if key was absent
- Call using() before createTestSuite().
- Call named() before createTestSuite().
- Call withFeatures() before createTestSuite().
AI-assisted analysis of google/guava@94f39958ba (2026-08-13).
Data as JSON: /api/errors/4d9d1457af055449.
Report an issue: GitHub.