Python IndexError pop from empty list: 4 Fixes (2026)

IndexError: pop from empty list happens when you call list.pop() on an empty list. This is one of the most common Python bugs in queues, stacks, work-stealing loops, and item-by-item processors. Here are 4 patterns to handle it cleanly.

Python IndexError pop from empty list 4 Fixes (2026)

Minimal reproducer

queue = []
item = queue.pop()  # IndexError: pop from empty list

Fix 1: Check length before popping

while queue:
    item = queue.pop()
    process(item)

# Or as a one-liner with conditional expression
item = queue.pop() if queue else None

The truthiness check if queue is the most Pythonic way to test if a list is non-empty. Same applies to dicts, sets, and strings.

Fix 2: try/except for race conditions

try:
    item = queue.pop()
except IndexError:
    item = None  # or break, or sleep and retry

Use this pattern in multi-threaded code where another thread might pop between your length-check and your pop. The try/except is atomic; the check-then-pop is not.

Fix 3: collections.deque for safe popping with timeout

from collections import deque
queue = deque([1, 2, 3])

# Pop from left (FIFO) or right (LIFO)
while queue:
    item = queue.popleft()  # O(1), unlike list.pop(0) which is O(n)
    process(item)

For producer-consumer patterns, switch to collections.deque (O(1) popleft) or queue.Queue (thread-safe with blocking get).

Fix 4: Sentinel default with no exception

SENTINEL = object()

def safe_pop(lst, default=SENTINEL):
    return lst.pop() if lst else default

item = safe_pop(queue)
if item is SENTINEL:
    print("Queue empty, nothing to do")
else:
    process(item)

When to use each

ScenarioBest pattern
Single-threaded loopwhile queue: queue.pop()
Multi-threaded queuequeue.Queue with blocking get
FIFO from frontcollections.deque.popleft()
Concurrent producer/consumerasyncio.Queue or queue.Queue

Frequently Asked Questions

What is the difference between list.pop() and list.pop(0)?

list.pop() removes the last item (O(1)). list.pop(0) removes the first item (O(n), because all remaining items shift left). For FIFO queues, use collections.deque.popleft() instead, which is O(1).

Why does my pop() fail intermittently in multi-threaded code?

Race condition. Thread A checks “if queue”, sees items, then Thread B pops the last item, then Thread A tries to pop and gets IndexError. Use try/except IndexError (atomic) or queue.Queue (thread-safe with blocking).

Is list.pop() equivalent to del list[-1]?

Almost. Both remove the last item. pop() returns it, del does not. Both raise IndexError on empty list. Use pop() when you need the value, del when you only need to remove.

How do I implement a thread-safe stack in Python?

For LIFO stacks, queue.LifoQueue is thread-safe with blocking put/get. For LIFO with non-blocking, wrap a list in a threading.Lock. For async code, use asyncio.LifoQueue.

Can I catch IndexError without try/except in modern Python?

For checking-not-handling, just use truthy test (if queue: …). For handling, contextlib.suppress(IndexError) is a one-line alternative to try/except pass. Python 3.10+ structural pattern matching can also handle it with case [first, *rest]: cases.

Leave a Comment