{"record":{"id":"c8f7fcaee05aaa4c","repo":"apache/hadoop","slug":"key-is-not-a-member","errorCode":null,"errorMessage":"Key is not a member","messagePattern":"Key is not a member","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/bloom/CountingBloomFilter.java","lineNumber":140,"sourceCode":"      if(bucketValue < BUCKET_MAX_VALUE) {\n        // increment by 1\n        buckets[wordNum] = (buckets[wordNum] & ~bucketMask) | ((bucketValue + 1) << bucketShift);\n      }\n    }\n  }\n\n  /**\n   * Removes a specified key from <i>this</i> counting Bloom filter.\n   * <p>\n   * <b>Invariant</b>: nothing happens if the specified key does not belong to <i>this</i> counter Bloom filter.\n   * @param key The key to remove.\n   */\n  public void delete(Key key) {\n    if(key == null) {\n      throw new NullPointerException(\"Key may not be null\");\n    }\n    if(!membershipTest(key)) {\n      throw new IllegalArgumentException(\"Key is not a member\");\n    }\n\n    int[] h = hash.hash(key);\n    hash.clear();\n\n    for(int i = 0; i < nbHash; i++) {\n      // find the bucket\n      int wordNum = h[i] >> 4;          // div 16\n      int bucketShift = (h[i] & 0x0f) << 2;  // (mod 16) * 4\n      \n      long bucketMask = 15L << bucketShift;\n      long bucketValue = (buckets[wordNum] & bucketMask) >>> bucketShift;\n      \n      // only decrement if the count in the bucket is between 0 and BUCKET_MAX_VALUE\n      if(bucketValue >= 1 && bucketValue < BUCKET_MAX_VALUE) {\n        // decrement by 1\n        buckets[wordNum] = (buckets[wordNum] & ~bucketMask) | ((bucketValue - 1) << bucketShift);\n      }","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/bloom/CountingBloomFilter.java#L122-L158","documentation":"CountingBloomFilter.delete(Key) first calls membershipTest(key); if the filter does not currently report the key as a member, it throws IllegalArgumentException('Key is not a member'). Deleting a non-member would decrement counters that other keys rely on, corrupting the filter, so it is forbidden. (Note the javadoc above the method claims 'nothing happens' for non-members — the code actually throws, so trust the throw.)","triggerScenarios":"cbf.delete(key) for a key that was never added; deleting a key that was already deleted once (second delete fails membership); deleting after and()-ing the filter with another filter wiped the counters; deleting a key whose add() was rolled back by an exception mid-loop.","commonSituations":"Remove-on-expiry loops where the same key is processed twice; sets rebuilt from serialized filters where prior adds were lost; compensating transactions that delete records that were never inserted; the (rare) false-positive direction does not cause this — only false negatives (from filter corruption or mismatched shape) make an added key test as non-member.","solutions":["Only delete keys you have previously added with the same filter instance.","Guard with if (cbf.membershipTest(key)) cbf.delete(key);","Make removal idempotent: mark keys processed (e.g. a secondary set) so double-deletes cannot occur.","Never delete after shape-altering operations (and/xor) unless you know membership still holds; rebuild instead."],"exampleFix":"// before\ncbf.delete(key); // key was never added (or already deleted)\n// throws IllegalArgumentException: Key is not a member\n\n// after\nif (cbf.membershipTest(key)) {\n  cbf.delete(key);\n}","handlingStrategy":"validation","validationCode":"// idempotent delete: only remove keys the filter still reports\nif (cbf.membershipTest(key)) {\n  cbf.delete(key);\n} else {\n  LOG.debug(\"Key not present; nothing to delete\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  cbf.delete(key);\n} catch (IllegalArgumentException e) {\n  // 'Key is not a member': already deleted or never added — treat as no-op\n  LOG.debug(\"Ignored delete of non-member key\", e);\n}","preventionTips":["Track processed keys in a side set to prevent double-deletes in retry/replay loops.","Only delete keys previously added to the same filter instance.","Do not delete after and()/xor() shape operations; rebuild the filter instead.","Remember counting-bloom deletes are not idempotent — one delete per add."],"tags":["bloom-filter","counting-bloom-filter","state-violation","precondition","hadoop-common"],"backgroundTag":"bloom-filter-delete-nonmember","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}