{"record":{"id":"10b0d4689ae97e90","repo":"arduino/Arduino","slug":"dictionary-is-empty","errorCode":null,"errorMessage":"dictionary is empty","messagePattern":"dictionary is empty","errorType":"exception","errorClass":"KeyError","httpStatus":null,"severity":"error","filePath":"arduino-core/src/processing/app/i18n/python/requests/packages/urllib3/packages/ordered_dict.py","lineNumber":98,"sourceCode":"    def clear(self):\n        'od.clear() -> None.  Remove all items from od.'\n        try:\n            for node in self.__map.itervalues():\n                del node[:]\n            root = self.__root\n            root[:] = [root, root, None]\n            self.__map.clear()\n        except AttributeError:\n            pass\n        dict.clear(self)\n\n    def popitem(self, last=True):\n        '''od.popitem() -> (k, v), return and remove a (key, value) pair.\n        Pairs are returned in LIFO order if last is true or FIFO order if false.\n\n        '''\n        if not self:\n            raise KeyError('dictionary is empty')\n        root = self.__root\n        if last:\n            link = root[0]\n            link_prev = link[0]\n            link_prev[1] = root\n            root[0] = link_prev\n        else:\n            link = root[1]\n            link_next = link[1]\n            root[1] = link_next\n            link_next[0] = root\n        key = link[2]\n        del self.__map[key]\n        value = dict.pop(self, key)\n        return key, value\n\n    # -- the following methods do not depend on the internal structure --\n","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/arduino/Arduino/blob/a0df6e0e83b652c72bc78b0a1376c54d6ebc3bee/arduino-core/src/processing/app/i18n/python/requests/packages/urllib3/packages/ordered_dict.py#L80-L116","documentation":"OrderedDict.popitem() raises KeyError('dictionary is empty') when called on an OrderedDict that contains no items, because there is no (key, value) pair to remove and return. The vendored ordered_dict.py checks `if not self:` first and aborts rather than unlinking from an empty linked list. Unlike a plain dict, the message explicitly names the empty-container cause instead of a missing key.","triggerScenarios":"Calling od.popitem() (with or without last=True/False) on an OrderedDict created empty or whose entries were all already removed; also hit when a draining loop calls popitem() one time more than the dict size.","commonSituations":"Looping `while True: od.popitem()` to drain a cache or LRU without checking emptiness; reusing an OrderedDict after a previous drain pass; concurrent code removing items between a size check and the popitem() call.","solutions":["Guard with `if od: od.popitem()` before popping.","Wrap the call in try/except KeyError to treat empty as a normal stop condition.","Replace the drain loop with `for _ in range(len(od)): od.popitem()` or iterate over list(od.items())."],"exampleFix":"// before\nwhile True:\n    k, v = cache.popitem()\n    process(k, v)\n// after\nwhile cache:\n    k, v = cache.popitem()\n    process(k, v)","handlingStrategy":"validation","validationCode":"if od:  # or: len(od) > 0\n    k, v = od.popitem()\nelse:\n    k, v = None, None","typeGuard":"def can_popitem(od):\n    return isinstance(od, dict) and len(od) > 0","tryCatchPattern":"try:\n    k, v = od.popitem()\nexcept KeyError:\n    k, v = None, None  # dict is empty","preventionTips":["Check `if od:` before any popitem call.","Bound drain loops by the dict's current length instead of looping until failure.","Re-check emptiness after any concurrent mutation of the dict."],"tags":["python","keyerror","ordered-dict","empty-collection"],"backgroundTag":"resource-not-found","analyzedSha":"a0df6e0e83b652c72bc78b0a1376c54d6ebc3bee","analyzedAt":"2026-09-06T10:13:38.901Z","contentChangedAt":"2026-09-06T10:13:38.901Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}