{"record":{"id":"9c5090af3997ca82","repo":"google/guava","slug":"should-not-call-merge-function-if-key-was-mapped-t","errorCode":null,"errorMessage":"Should not call merge function if key was mapped to null","messagePattern":"Should not call merge function if key was mapped to null","errorType":"exception","errorClass":"AssertionFailedError","httpStatus":null,"severity":"error","filePath":"android/guava-testlib/src/com/google/common/collect/testing/testers/MapMergeTester.java","lineNumber":76,"sourceCode":"                  throw new AssertionFailedError(\n                      \"Should not call merge function if key was absent\");\n                }));\n    expectAdded(e3());\n  }\n\n  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_VALUES})\n  @CollectionSize.Require(absent = ZERO)\n  public void testMappedToNull() {\n    initMapWithNullValue();\n    assertEquals(\n        \"Map.merge(keyMappedToNull, value, function) should return value\",\n        v3(),\n        getMap()\n            .merge(\n                getKeyForNullValue(),\n                v3(),\n                (oldV, newV) -> {\n                  throw new AssertionFailedError(\n                      \"Should not call merge function if key was mapped to null\");\n                }));\n    expectReplacement(entry(getKeyForNullValue(), v3()));\n  }\n\n  @MapFeature.Require({SUPPORTS_PUT, ALLOWS_NULL_KEYS})\n  public void testMergeAbsentNullKey() {\n    assertEquals(\n        \"Map.merge(null, value, function) should return value\",\n        v3(),\n        getMap()\n            .merge(\n                null,\n                v3(),\n                (oldV, newV) -> {\n                  throw new AssertionFailedError(\n                      \"Should not call merge function if key was absent\");\n                }));","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/google/guava/blob/94f39958baf7ad51ddf9c70e406ed6b188194daa/android/guava-testlib/src/com/google/common/collect/testing/testers/MapMergeTester.java#L58-L94","documentation":"Thrown inside the remapping function of MapMergeTester.testMappedToNull. Per the Map.merge contract, when the key is present but mapped to null, the function MUST NOT be invoked; merge should treat null as 'no value' and insert the new value. This firing means your Map calls the function for a null-mapped key.","triggerScenarios":"Running MapTestSuiteBuilder (with ALLOWS_NULL_VALUES, size != ZERO) against your Map; testMappedToNull initializes a null value and calls merge. Your implementation calls the BiFunction instead of treating null as absent.","commonSituations":"A merge() that distinguishes 'contains key' from 'value non-null' incorrectly, calling apply() whenever containsKey(k) regardless of the stored null; Map implementations wrapping null values in a sentinel.","solutions":["Treat a present-but-null value exactly like an absent mapping in merge: do not call the function, just store the new value.","Mirror HashMap.merge semantics: oldValue == null (whether absent or explicitly null) -> store value without invoking the function.","Ensure the ALLOWS_NULL_VALUES path is exercised in your own unit tests."],"exampleFix":"// before\nV old = containsKey(k) ? get(k) : DEFAULT;\nV merged = f.apply(old, v); // BUG: called when get(k)==null\n\n// after\nV old = get(k);\nif (old == null) { put(k, v); return v; } // null value treated as absent\nV merged = f.apply(old, v);\nif (merged == null) remove(k); else put(k, merged);\nreturn merged;","handlingStrategy":"validation","validationCode":"// Ensure null-mapped value is treated as absent.\nMap<K,V> m = newMap();\nm.put(k, null);\nm.merge(k, v, (o,n) -> { throw new AssertionFailedError(\"f must not be called for null value\"); });\nassertEquals(v, m.get(k));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["In merge(), treat get(k)==null the same whether the key is absent or explicitly mapped to null.","Test the ALLOWS_NULL_VALUES merge path explicitly in your own suite."],"tags":["guava-testlib","map-contract","merge","null-values","assertion"],"backgroundTag":null,"analyzedSha":"94f39958baf7ad51ddf9c70e406ed6b188194daa","analyzedAt":"2026-08-13T22:50:30.265Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}