microsoft/semantic-kernel · error · ValueError
task_done() called too many times
Error message
task_done() called too many times
What it means
The Queue tracks unfinished tasks: incremented on put(), decremented on task_done(). If task_done() is called more times than items were put (i.e. _unfinished_tasks <= 0), ValueError is raised. This mirrors the standard asyncio.Queue contract. shutdown(immediate=True) calls task_done() for each remaining item.
Source
Thrown at python/semantic_kernel/agents/runtime/in_process/queue.py:232
def task_done(self) -> None:
"""Indicate that a formerly enqueued task is complete.
Used by queue consumers. For each get() used to fetch a task,
a subsequent call to task_done() tells the queue that the processing
on the task is complete.
If a join() is currently blocking, it will resume when all items have
been processed (meaning that a task_done() call was received for every
item that had been put() into the queue).
shutdown(immediate=True) calls task_done() for each remaining item in
the queue.
Raises ValueError if called more times than there were items placed in
the queue.
"""
if self._unfinished_tasks <= 0:
raise ValueError("task_done() called too many times")
self._unfinished_tasks -= 1
if self._unfinished_tasks == 0:
self._finished.set()
async def join(self) -> None:
"""Block until all items in the queue have been gotten and processed.
The count of unfinished tasks goes up whenever an item is added to the
queue. The count goes down whenever a consumer calls task_done() to
indicate that the item was retrieved and all work on it is complete.
When the count of unfinished tasks drops to zero, join() unblocks.
"""
if self._unfinished_tasks > 0:
await self._finished.wait()
def shutdown(self, immediate: bool = False) -> None:
"""Shut-down the queue, making queue gets and puts raise QueueShutDown.
View on GitHub (pinned to c028a0c7dc)
Solutions
- Do not call task_done() on the runtime's internal queue — the runtime manages this internally.
- If you have a custom Queue subclass, ensure task_done() is called exactly once per get()/put() pair.
- Check for double-processing or duplicate consumer tasks that may call task_done() twice.
Example fix
# before item = await queue.get() queue.task_done() queue.task_done() # raises on second call # after item = await queue.get() queue.task_done() # exactly once per item
Defensive patterns
Strategy: validation
Validate before calling
# Users should not call task_done() on the runtime's internal queue.
# If managing your own queue, track task_done calls:
class SafeQueue:
def __init__(self):
self._done_count = 0
self._put_count = 0
def safe_task_done(self, queue):
if self._done_count >= self._put_count:
raise ValueError('task_done called too many times')
queue.task_done()
self._done_count += 1 Type guard
null
Try / catch
try:
queue.task_done()
except ValueError:
pass # already accounted for — ignore Prevention
- Do not call task_done() on the runtime's internal queue — the runtime manages it.
- In custom queue subclasses, call task_done() exactly once per put()/get() pair.
- Watch for duplicate consumer tasks that double-process items.
When it happens
Trigger: Calling task_done() on the queue more times than items were added — e.g. a consumer calling task_done() twice per item, or calling it after shutdown(immediate=True) already drained and accounted for all items. Also triggered by a race where task_done is called for an item that was never put.
Common situations: Custom message processing code that calls task_done() manually (it should normally not be called by users — the runtime manages it internally). A bug in the runtime's internal queue management where task_done accounting goes negative.
Related errors
- {self!r} is bound to a different event loop
- Agent with name {agentId.Type} not found.
- receive_task must be an instance of asyncio.Task or None
- The invocation was canceled before it could complete.
- AgentInstantiationContext cannot be instantiated. It is a st
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/d5bc7c61b13a095a.
Report an issue: GitHub.