Python queue.Empty exception (tested)

queue.Empty (shown as _queue.Empty in tracebacks) means a non-blocking or timed get() found nothing. We measured which calls raise it on Python 3.13.5 and which similar queues raise something else.

1. When queue.Empty is raised

import queue
q = queue.Queue()
for call in ("q.get_nowait()", "q.get(block=False)", "q.get(timeout=0.5)"):
    try:
        eval(call)
    except Exception as e:
        print(f"{call:20} -> {type(e).__module__}.{type(e).__name__} {str(e)!r}")
print("queue.Empty is IndexError?", issubclass(queue.Empty, IndexError))
print("bases:", queue.Empty.__mro__[1:])

Output:

q.get_nowait()       -> _queue.Empty ''
q.get(block=False)   -> _queue.Empty ''
q.get(timeout=0.5)   -> _queue.Empty ''
queue.Empty is IndexError? False
bases: (<class 'Exception'>, <class 'BaseException'>, <class 'object'>)

Measured on Python 3.13.5: get_nowait(), get(block=False) and get(timeout=...) on an empty queue all raise queue.Empty with an empty message, so a traceback ends in a bare _queue.Empty (the C module's name for the same class). A plain q.get() never raises it: it waits forever. queue.Empty is not an IndexError, so code that catches IndexError as you would for list.pop() misses it. Catch queue.Empty.

2. multiprocessing uses queue.Empty, asyncio doesn't

import asyncio, queue, multiprocessing
mq = multiprocessing.Queue()
try:
    mq.get(timeout=0.2)
except queue.Empty:
    print("multiprocessing.Queue raises queue.Empty")

async def main():
    aq = asyncio.Queue()
    try:
        aq.get_nowait()
    except queue.Empty:
        print("caught as queue.Empty")
    except asyncio.QueueEmpty as e:
        print("asyncio.Queue raises asyncio.QueueEmpty, not queue.Empty:",
              issubclass(asyncio.QueueEmpty, queue.Empty))
asyncio.run(main())

Output:

multiprocessing.Queue raises queue.Empty
asyncio.Queue raises asyncio.QueueEmpty, not queue.Empty: False

Measured: multiprocessing.Queue raises the same queue.Empty, but asyncio.Queue.get_nowait() raises asyncio.QueueEmpty, which is a separate class. An except queue.Empty in async code doesn't catch it. For the list version of this error, see our pop from empty list guide.

3. Worker threads: block on get() and send a stop marker

import queue, threading, time
q = queue.Queue()
STOP = object()
handled = {}
def worker(n):
    done = 0
    while (item := q.get()) is not STOP:   # blocks; no Empty, no busy loop
        time.sleep(0.001)                  # simulate work
        done += 1
    handled[n] = done
threads = [threading.Thread(target=worker, args=(n,)) for n in range(3)]
for t in threads: t.start()
for i in range(30):
    q.put(i)
for _ in threads:
    q.put(STOP)                            # one stop marker per worker
for t in threads: t.join()
print("items handled per worker:", dict(sorted(handled.items())), "total:", sum(handled.values()))

Output:

items handled per worker: {0: 10, 1: 10, 2: 10} total: 30

Measured: instead of polling with get_nowait() and catching Empty, let each worker block on get() and put one stop marker per worker on the queue when the work is done. All 30 items were handled and every thread exited. A while not q.empty() loop is not a safe alternative with several consumers: the Python docs note that empty() gives no guarantee the next get() won't block. (Our test with 8 threads didn't hit that race, but it's timing-dependent.)

Frequently asked questions

When does Python raise queue.Empty?

When get_nowait(), get(block=False) or get(timeout=...) finds the queue empty. We measured all three on Python 3.13.5; a plain get() waits instead of raising.

Why is the traceback just _queue.Empty with no message?

queue.Empty is raised without a message, and _queue is the C module that defines it. We measured an empty str() for all three calls.

Does except IndexError catch queue.Empty?

No. We checked queue.Empty's bases: it subclasses Exception directly, not IndexError.

Is asyncio.QueueEmpty the same as queue.Empty?

No. We measured asyncio.Queue.get_nowait() raising asyncio.QueueEmpty, which is not a subclass of queue.Empty, while multiprocessing.Queue raises queue.Empty.

Written with AI assistance. Measured on 2026-10-09 with Python 3.13.5: get_nowait/get(block=False)/get(timeout) on an empty queue.Queue, multiprocessing.Queue and asyncio.Queue, and three worker threads with stop markers. Every block was run verbatim and its output pasted from that run. PlainHeaders is our extension; everything else here is built-in Python.