{"record":{"id":"8c609472057909d3","repo":"TheAlgorithms/Python","slug":"remove-first-from-empty-list","errorCode":null,"errorMessage":"remove_first from empty list","messagePattern":"remove_first from empty list","errorType":"exception","errorClass":"IndexError","httpStatus":null,"severity":"error","filePath":"data_structures/linked_list/deque_doubly.py","lineNumber":122,"sourceCode":"\n    def remove_first(self):\n        \"\"\"removal from the front\n        >>> d = LinkedDeque()\n        >>> d.is_empty()\n        True\n        >>> d.remove_first()\n        Traceback (most recent call last):\n           ...\n        IndexError: remove_first from empty list\n        >>> d.add_first('A') # doctest: +ELLIPSIS\n        <data_structures.linked_list.deque_doubly.LinkedDeque object at ...\n        >>> d.remove_first()\n        'A'\n        >>> d.is_empty()\n        True\n        \"\"\"\n        if self.is_empty():\n            raise IndexError(\"remove_first from empty list\")\n        return self._delete(self._header._next)\n\n    def remove_last(self):\n        \"\"\"removal in the end\n        >>> d = LinkedDeque()\n        >>> d.is_empty()\n        True\n        >>> d.remove_last()\n        Traceback (most recent call last):\n           ...\n        IndexError: remove_first from empty list\n        >>> d.add_first('A') # doctest: +ELLIPSIS\n        <data_structures.linked_list.deque_doubly.LinkedDeque object at ...\n        >>> d.remove_last()\n        'A'\n        >>> d.is_empty()\n        True\n        \"\"\"","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/TheAlgorithms/Python/blob/f5988cc09713315817df6a7e327e258013a94440/data_structures/linked_list/deque_doubly.py#L104-L140","documentation":"LinkedDeque.remove_first() raises IndexError('remove_first from empty list') when _delete would be called on the header sentinel itself. This is the correct, documented behavior (see doctest) and the exception type matches CPython's collections.deque.popleft on empty.","triggerScenarios":"Calling remove_first() more times than elements were added: e.g. add_first('A') once, then remove_first() twice; or calling it on a brand-new LinkedDeque.","commonSituations":"Unbalanced pop/push loops where consumers drain faster than producers; worker loops that assume a blocking queue but this deque is non-blocking; retry logic that pops an item then pops again on failure.","solutions":["Check is_empty() before each remove_first() in loops: 'while not d.is_empty(): item = d.remove_first()'.","Catch IndexError specifically — this method (unlike first()/last()) raises IndexError, so 'except IndexError' is precise here.","Track in-flight counts so a failed consumer does not issue a compensating extra pop."],"exampleFix":"# before\nitem = d.remove_first()  # IndexError on empty\n# after\nitem = d.remove_first() if not d.is_empty() else None","handlingStrategy":"validation","validationCode":"while not d.is_empty():\n    item = d.remove_first()","typeGuard":null,"tryCatchPattern":"try:\n    item = d.remove_first()\nexcept IndexError:\n    item = None  # deque drained","preventionTips":["Drive consumer loops with is_empty(), not a fixed iteration count.","Catch IndexError here — this method uses the right exception type.","Audit retry handlers so a failed pop does not trigger a second pop."],"tags":["deque","index-error","empty-collection","pop"],"backgroundTag":null,"analyzedSha":"f5988cc09713315817df6a7e327e258013a94440","analyzedAt":"2026-08-14T17:30:07.041Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}