{"record":{"id":"9e922cd8367cd7e3","repo":"stanfordnlp/CoreNLP","slug":"cannot-remove-from-key-set","errorCode":null,"errorMessage":"Cannot remove from key set","messagePattern":"Cannot remove from key set","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/stats/Counters.java","lineNumber":2767,"sourceCode":"      }\n\n      public Set<E> keySet() {\n        return new AbstractSet<E>() {\n          @Override\n          public Iterator<E> iterator() {\n            return new Iterator<E>() {\n              Iterator<E> it = map.keySet().iterator();\n\n              public boolean hasNext() {\n                return it.hasNext();\n              }\n\n              public E next() {\n                return it.next();\n              }\n\n              public void remove() {\n                throw new UnsupportedOperationException(\"Cannot remove from key set\");\n              }\n            };\n          }\n\n          @Override\n          public int size() {\n            return map.size();\n          }\n        };\n      }\n\n      public double remove(E key) {\n        final Number removed = map.remove(key);\n        if (removed != null) {\n          final double rv = removed.doubleValue();\n          total -= rv;\n          return rv;\n        }","sourceCodeStart":2749,"sourceCodeEnd":2785,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/stats/Counters.java#L2749-L2785","documentation":"Counters.java wraps a counter's key set in an Iterator whose remove() is deliberately unsupported. The library exposes the key set for iteration only; mutating the backing counter through the iterator would corrupt the internal total maintained by the wrapper. Call UnsupportedOperationException to signal that structural removal must go through the Counter API instead.","triggerScenarios":"Calling java.util.Iterator.remove() while iterating counter.keySet() (or any view backed by this iterator), e.g. `for (E k : counter.keySet()) { it.remove(); }` or removing via the for-each collection's iterator.","commonSituations":"Developers pruning keys below a threshold or deleting zero-count entries while iterating a Counter, a pattern that works on plain HashMap keySets but not on this view.","solutions":["Collect keys to remove into a separate list, then call counter.remove(key) after iteration.","Use Counters.retainKeys(counter, predicate) or similar filtering helper instead of iterator.remove().","Build a new Counter containing only the keys you want to keep."],"exampleFix":"// before\nfor (Iterator<String> it = counter.keySet().iterator(); it.hasNext();) {\n  String k = it.next();\n  if (counter.getCount(k) < 0.5) it.remove(); // throws\n}\n// after\nList<String> toRemove = new ArrayList<>();\nfor (String k : counter.keySet()) {\n  if (counter.getCount(k) < 0.5) toRemove.add(k);\n}\ntoRemove.forEach(counter::remove);","handlingStrategy":"validation","validationCode":"if (counter == null || counter.keySet() == null) throw new IllegalArgumentException(\"counter must not be null\");\n// plan removals via keys, never via iterator.remove()","typeGuard":null,"tryCatchPattern":"// should never rely on catching; structure code to avoid iterator.remove()\ntry {\n  keySetIterator.remove();\n} catch (UnsupportedOperationException e) {\n  pendingRemovals.add(currentKey); // defer removal\n}","preventionTips":["Never call remove() on iterators of Counter collection views; treat them as read-only.","Collect keys during iteration and remove after the loop with counter.remove(key).","Prefer Counters.retainKeys/filtering helpers over manual iteration."],"tags":["unsupported-operation","iterator","collection"],"backgroundTag":"unsupported-operation","analyzedSha":"1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a","analyzedAt":"2026-09-10T02:24:07.274Z","contentChangedAt":"2026-09-10T02:24:07.274Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}