google/guava · error · AssertionFailedError
Should not call merge function if key was absent
Error message
Should not call merge function if key was absent
What it means
Thrown inside the remapping function of MapMergeTester.testAbsent as an AssertionFailedError. By the Map.merge contract, when the key is absent (or mapped to null) the remapping function MUST NOT be invoked. This assertion failing means the Map implementation under test incorrectly calls the function for an absent key.
Source
Thrown at android/guava-testlib/src/com/google/common/collect/testing/testers/MapMergeTester.java:58
* A generic JUnit test which tests {@link Map#merge}. Can't be invoked directly; please see {@link
* com.google.common.collect.testing.MapTestSuiteBuilder}.
*
* @author Louis Wasserman
*/
@GwtCompatible
@IgnoreJRERequirement // We opt into library desugaring for our tests.
public class MapMergeTester<K, V> extends AbstractMapTester<K, V> {
@MapFeature.Require(SUPPORTS_PUT)
public void testAbsent() {
assertEquals(
"Map.merge(absent, value, function) should return value",
v3(),
getMap()
.merge(
k3(),
v3(),
(oldV, newV) -> {
throw new AssertionFailedError(
"Should not call merge function if key was absent");
}));
expectAdded(e3());
}
@MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})
@CollectionSize.Require(absent = ZERO)
public void testMappedToNull() {
initMapWithNullValue();
assertEquals(
"Map.merge(keyMappedToNull, value, function) should return value",
v3(),
getMap()
.merge(
getKeyForNullValue(),
v3(),
(oldV, newV) -> {
throw new AssertionFailedError(View on GitHub (pinned to 94f39958ba)
Solutions
- In your Map.merge, check containsKey(k) (or get(k) == null && !containsKey) first; only call the function when a non-null existing value is present.
- Match the JDK HashMap.merge algorithm: if no mapping or mapping is null -> put value directly; else compute merged value.
- Re-run the suite; testAbsent should pass without invoking the function.
Example fix
// before
@Override public V merge(K k, V v, BiFunction<? super V,? super V,? extends V> f) {
V old = get(k);
V merged = f.apply(old, v); // BUG: called even when old is absent
put(k, merged);
return merged;
}
// after
@Override public V merge(K k, V v, BiFunction<? super V,? super V,? extends V> f) {
V old = get(k);
if (old == null) { put(k, v); return v; } // absent: do not call f
V merged = f.apply(old, v);
if (merged == null) remove(k); else put(k, merged);
return merged;
} Defensive patterns
Strategy: validation
Validate before calling
// Direct unit check before running the full suite.
Map<K,V> m = newMap();
m.merge(absentKey, v, (o,n) -> { throw new AssertionFailedError("f must not be called"); });
assertEquals(v, m.get(absentKey)); Prevention
- Implement merge() by checking absence/null-value first and only invoking the function for a present non-null value.
- Mirror HashMap.merge semantics in custom Map implementations.
When it happens
Trigger: Running the guava-testlib MapTestSuiteBuilder against your custom Map. Your Map.merge implementation invokes the BiFunction even when the key is absent, instead of simply inserting the value. The tester's @MapFeature.Require(SUPPORTS_PUT) testAbsent case trips this.
Common situations: Custom Map implementations that unconditionally compute newValue = remappingFunction.apply(old, new) before checking whether the key exists; copy-pasting an AbstractMap merge that does not short-circuit on absent keys.
Related errors
- Should not call merge function if key was mapped to null
- Should not call merge function if value was null
- 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/b61d9ae67874c74d.
Report an issue: GitHub.