python/cpython · error · ValueError
Wrong field count in {line!r}
Error message
Wrong field count in {line!r} What it means
Raised by asyncio queues when task_done() is called more times than items were put(). Every put() increments _unfinished_tasks and every task_done() decrements it; the count may not go below zero. The error means the application's get/task_done bookkeeping is unbalanced — typically task_done() called without a successful get(), or from multiple consumers for one item.
Source
Thrown at Doc/tools/extensions/c_annotations.py:94
# Defines how much of the struct is exposed. Only relevant for structs.
# Source: [<item_kind>.*.struct_abi_kind] in stable_abi.toml.
struct_abi_kind: str
def read_refcount_data(refcount_filename: Path) -> dict[str, RefCountEntry]:
refcount_data = {}
refcounts = refcount_filename.read_text(encoding="utf8")
for line in refcounts.splitlines():
line = line.strip()
if not line or line.startswith("#"):
# blank lines and comments
continue
# Each line is of the form
# function ':' type ':' [param name] ':' [refcount effect] ':' [comment]
parts = line.split(":", 4)
if len(parts) != 5:
raise ValueError(f"Wrong field count in {line!r}")
function, type, arg, refcount, _comment = parts
# Get the entry, creating it if needed:
try:
entry = refcount_data[function]
except KeyError:
entry = refcount_data[function] = RefCountEntry(function)
if not refcount or refcount == "null":
refcount = None
else:
refcount = int(refcount)
# Update the entry with the new parameter
# or the result information.
if arg:
entry.args.append((arg, type, refcount))
else:
entry.result_type = type
entry.result_refs = refcountView on GitHub (pinned to bc6749cc3b)
Solutions
- Call task_done() exactly once per successfully gotten item — audit all call sites
- Use the canonical worker shape: item = await q.get(); try: process(item) finally: q.task_done()
- Remove duplicate task_done() calls in exception handlers or retries; if you re-queue on failure, do it via put() so the counter rises again
- If you don't need join(), drop task_done()/join() entirely and use sentinel values or task cancellation for shutdown
Example fix
# before
while True:
item = await q.get()
q.task_done()
await handle(item) # if handle raises, finally path may call again
# after
while True:
item = await q.get()
try:
await handle(item)
finally:
q.task_done() Defensive patterns
Strategy: validation
Validate before calling
class TrackedQueue(asyncio.Queue):
def __init__(self):
super().__init__()
self._got = set()
async def get_tracked(self):
item = await super().get()
self._got.add(id(item))
return item
def task_done_safe(self, item):
if id(item) not in self._got:
raise ValueError('task_done without matching get')
self._got.discard(id(item))
super().task_done() Try / catch
try:
q.task_done()
except ValueError as e:
if 'too many times' in str(e):
logger.exception('unbalanced task_done; audit worker bookkeeping')
raise Prevention
- One task_done per successful get — put it in the finally of the worker loop
- Never call task_done in both except and outer finally for the same item
- On failure-requeue, put() the item again instead of double task_done
- Consider sentinel-based shutdown instead of join/task_done when counts get complex
When it happens
Trigger: Calling q.task_done() without a preceding q.get(); calling task_done() twice per item; a worker that calls task_done() in both a normal branch and an exception/finally branch for the same item; calling task_done() after get_nowait() on an item already accounted for.
Common situations: Worker-pool patterns with try/finally where task_done() is also called in the except path; refactoring a single-consumer queue to multiple consumers without adjusting bookkeeping; retry logic that re-processes an item and calls task_done() again; mixing join() coordination with manual deque operations.
Related errors
- Failed to fetch glossary.json
- d3-flame-graph library failed to load
- Not implemented
- Unimplemented ioctl request
- {htmldir!r} is not a Sphinx HTML output directory
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/2083fb8509b09f66.
Report an issue: GitHub.