apache/hadoop · error · ConcurrentModificationException

modification= != startModification =

Error message

modification={} != startModification = {}

What it means

LightWeightLinkedSet's iterator snapshots 'modification' as startModification when created; next() throws ConcurrentModificationException whenever any structural add/remove/clear happened since. Identical fail-fast semantics to LightWeightHashSet (3247), but note this iterator offers no remove() at all (3254), so the usual 'iterate and remove' workaround is not available here.

Solutions

  1. Collect then mutate: gather elements to remove/add during iteration, apply after the loop (required - iterator has no remove()).
  2. Iterate a copy: new ArrayList<>(set) or set.stream()... when mutation during traversal is expected.
  3. Externalize synchronization or use ConcurrentHashMap.newKeySet() when threads genuinely race.

Example fix

// before
for (T e : orderedSet) {
  if (expired(e)) orderedSet.remove(e); // next() -> ConcurrentModificationException
}

// after - snapshot iteration (iterator here has no remove())
for (T e : new ArrayList<>(orderedSet)) {
  if (expired(e)) orderedSet.remove(e);
}
Defensive patterns

Strategy: fallback

Validate before calling

// this iterator has NO remove() - always iterate a snapshot when mutating
List<T> snapshot = new ArrayList<>(orderedSet);
for (T e : snapshot) { if (expired(e)) orderedSet.remove(e); }

Prevention

When it happens

Trigger: for-each over a LightWeightLinkedSet while the same thread or another thread calls add/remove/clear on it - e.g., evicting expired entries inline.

Common situations: Expiry sweeps over insertion-ordered trackers; concurrent RPC threads mutating a shared set; re-entrant code adding during iteration.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/a9847990986c1128. Report an issue: GitHub.

Appendix: source

Thrown at hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/util/LightWeightLinkedSet.java:253

  public Iterator<T> iterator() {
    return new LinkedSetIterator();
  }

  private class LinkedSetIterator implements Iterator<T> {
    /** The starting modification for fail-fast. */
    private final int startModification = modification;
    /** The next element to return. */
    private DoubleLinkedElement<T> next = head;

    @Override
    public boolean hasNext() {
      return next != null;
    }

    @Override
    public T next() {
      if (modification != startModification) {
        throw new ConcurrentModificationException("modification="
            + modification + " != startModification = " + startModification);
      }
      if (next == null) {
        throw new NoSuchElementException();
      }
      final T e = next.element;
      // find the next element
      next = next.after;
      return e;
    }

    @Override
    public void remove() {
      throw new UnsupportedOperationException("Remove is not supported.");
    }
  }

  /**

View on GitHub (pinned to 2add963021)