python/cpython · error · KeyError
pop from empty WeakSet
Error message
pop from empty WeakSet
What it means
WeakSet.pop loops popping references from the internal set self.data; if that set is empty the underlying set.pop raises KeyError, which is re-raised (chained suppression via `from None`) as KeyError('pop from empty WeakSet'). The loop also skips dead references, so a set holding only dead weakrefs also behaves as empty.
Source
Thrown at Lib/_weakrefset.py:59
def __reduce__(self):
return self.__class__, (list(self),), self.__getstate__()
def add(self, item):
self.data.add(ref(item, self._remove))
def clear(self):
self.data.clear()
def copy(self):
return self.__class__(self)
def pop(self):
while True:
try:
itemref = self.data.pop()
except KeyError:
raise KeyError('pop from empty WeakSet') from None
item = itemref()
if item is not None:
return item
def remove(self, item):
self.data.remove(ref(item))
def discard(self, item):
self.data.discard(ref(item))
def update(self, other):
for element in other:
self.add(element)
def __ior__(self, other):
self.update(other)
return self
View on GitHub (pinned to bc6749cc3b)
Solutions
- Guard with a length/emptiness check, tolerating the GC race: try: item = ws.pop() except KeyError: handle-empty
- Prefer discard/remove or iteration when order does not matter
- Keep strong references to items that must survive (e.g. a companion list) so GC cannot empty the set unexpectedly
Example fix
# before
item = ws.pop() # KeyError: pop from empty WeakSet
# after
try:
item = ws.pop()
except KeyError:
item = None Defensive patterns
Strategy: try-catch
Validate before calling
def weakset_pop(ws):
try:
return ws.pop()
except KeyError:
return None # or a sentinel / default Type guard
def weakset_alive(ws) -> list:
return [r for r in ws if r is not None] Try / catch
try:
item = observers.pop()
except KeyError: # includes 'pop from empty WeakSet'
item = None Prevention
- Treat WeakSet.pop like set.pop: expect KeyError when empty
- Check emptiness with `if not ws:` right before popping, but still catch KeyError for the GC race
- Hold strong references to entries that must not vanish (companion list)
When it happens
Trigger: WeakSet().pop(); or .pop() on a WeakSet whose elements were garbage-collected (all remaining refs are dead) — mirroring set.pop semantics for emptiness.
Common situations: Using WeakSet for caches/observer registries and popping without checking; entries silently removed by GC make 'len()>0 just checked' races common in observer patterns.
Related errors
- timezone changed during initialization
- Day of month directive '%d' may not be used without a year d
- strptime() argument {} must be str, not {}
- stray %% in format '%s'
- '%s' is a bad directive in format '%s'
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/822980b9d3b2a1b9.
Report an issue: GitHub.