You hand a batch of items to a fleet of parallel agents. They finish, every one of them reports success, and the batch is declared done. Later someone notices that a few items were never touched. No agent failed, because no agent was ever given them. The work list itself was short before the first agent started.
This is a failure mode we have hit in our own batch work, and it is the same mechanism every time. The orchestrating model writes the list of items by hand, or re-types it from a directory listing, a search result or its own earlier message, and entries are dropped or duplicated on the way. Nothing downstream can notice, because each worker succeeds on exactly what it was given. This post describes the mechanism, names the three places a list gets corrupted, and gives the reconciliation pattern that makes the gap visible. It states no failure rate, because the rate depends on the list, and the fix works at any rate.
- 01The fault is in the work list, not the workers. Every worker succeeds on what it was given.A dropped item produces no error anywhere. The only signal is a count that does not match, and only if someone kept the count.
- 02Lists get corrupted in three places: hand-typing, truncated tool output, and a model summarising a list it should have copied.All three happen inside the orchestrator's own turn, before any delegation. All three are avoided by generating the list with code from the source of truth.
- 03The fix is a count and a reconciliation, not a smarter agent.Generate the assignment programmatically, record the count, pass identifiers not prose, and compare completed identifiers to the original set before saying done. Four invariants, all cheap.
- 04Retries make it worse when they are built from memory.A retry that re-types the remaining items reintroduces the corruption. Retry only the reconciled remainder, read from the same file the first pass used.
01 — The mechanismThe shape of the failure
The concrete shape is always the same. Forty items exist in a source of truth: a directory, a database query, a spreadsheet, a search result. The orchestrator reads them, writes a list of forty into its plan, and splits it across four workers. Each worker processes its ten, reports ten done, and returns. The orchestrator sums four reports of success and declares the batch complete.
Except the list it wrote had thirty-seven entries, or had forty with one item twice and three missing. A directory listing was long enough to be truncated in the tool output. A search returned a page of results and the model summarised it. The model re-typed the list from its own earlier message and skipped a line. In each case the list looked complete, the workers were given a complete looking slice, and the counts the orchestrator compared were counts of its own list, not of the source.
Success is measured against the list, and the list is the thing that was wrong
Every layer below the orchestrator does its job. The workers succeed, the tool calls return, the logs are clean. The batch is short by exactly the number of entries the orchestrator lost while writing the list, and the only place that number exists is in the difference between the source and the list, which nobody computed.
02 — The causesThree places a list gets corrupted
All three happen inside the orchestrator's own turn, before any worker exists. That is what makes them hard to see: the multi-agent machinery is not involved yet, and the logs of that machinery are where people look.
Hand-typed from a source
The orchestrator reads forty file names or forty identifiers and writes them into its plan as text. Transcription by a language model is lossy in the same way transcription by a person is: a skipped line, a repeated line, an identifier with two characters swapped. The list is then the plan, and the source is never consulted again.
Truncated tool output
A listing or a query result longer than the tool's output limit comes back cut, sometimes with a marker and sometimes without. The model treats what it received as the whole. Every item past the cut is absent from every downstream step, and no count was taken before the cut.
Summarised instead of copied
Asked to carry a list across a turn, a model may summarise it: "the twelve posts from the September batch" instead of the twelve slugs. The summary is then expanded from memory later, and the expansion is not the original. Context compaction does the same thing to a list held only in conversation.
The third case is the one that gets past careful people, because the list was correct once. It was correct in the tool output, it was correct in the first plan, and it became a paraphrase somewhere between turns. Our compaction checks reference covers what else goes missing when a long session is compressed; a work list held only in conversation is on that list.
03 — The vendorsWhat the vendors say
None of this is a house theory. The three largest publishers of agent tooling describe the same division of responsibility in their own guidance, and each puts the list on the deterministic side of the line.
Anthropic's engineering account of its multi-agent research system, published June 13, 2025, says each subagent needs an objective, an output format, tool guidance and clear task boundaries, and that without detailed task descriptions agents "duplicate work, leave gaps, or fail to find necessary information". Its worked example is two subagents investigating the same supply-chain question while a third covered something else, with no effective division of labour. That is the duplication half of the failure described here; the gap half is the same defect seen from the other side.
OpenAI's Agents SDK documentation on orchestrating multiple agents draws the line explicitly: orchestration by an LLM is powerful, but orchestration via code "makes tasks more deterministic and predictable, in terms of speed, cost and performance", with running agents in parallel through ordinary language primitives as one of its listed patterns. The list of what to run in parallel is exactly the kind of thing that page puts in code.
Google's Agent Development Kit describes its parallel workflow agent as deterministic in how it executes its sub-agents and not controlled by a model, with each sub-agent in its own branch and no automatic sharing of state between branches. It also notes that the order of collected results may not be deterministic, which is a reminder that results have to be matched to assignments by identifier, not by position.
Without detailed task descriptions, agents duplicate work, leave gaps, or fail to find necessary information.Anthropic, How we built our multi-agent research system, June 13, 2025
04 — The fixThe reconciliation pattern
The pattern has four invariants. Each is a line of code or a single assertion, and together they make a dropped item impossible to miss. The orchestrating model still decides what to do with each item; it just stops being the thing that decides which items exist.
- The list is generated, not writtenA script reads the source of truth and emits identifiers to a file. The model never types an identifier it did not read from that file. If the source is a tool call, the script handles pagination and truncation, and fails loudly if the output was cut.
- list = f(source)
- The count travels with the workThe script records the count beside the list. Every worker prompt carries the count of its own slice, and the orchestrator's completion check starts from the total, not from a sum of worker reports.
- count(list) = N
- Slices partition the setWorkers receive identifiers, not prose. The slices are computed so that their union is the list and their pairwise intersection is empty. A worker echoes the identifiers it received before starting, so a mismatch surfaces before any work is done.
- ∪ slices = list, ∩ = ∅
- Done means reconciledEach worker writes the identifiers it completed. The orchestrator computes the set difference between the original list and the union of completed sets. The batch is done when that difference is empty, and not before. Anything left is the retry set.
- list − done = ∅
The reconciliation step is the one people skip, because a sum of successes feels like the same check. It is not. Four workers reporting ten each is forty against the list; only the set difference is forty against the source. The same identifiers also make a run reproducible, which is the subject of our replay reference, and they keep fan-out inside the limits in our parallel-agent resource reference, because the slice size is now a number you chose rather than a guess the model made.
05 — In practiceThe checklist, and why retries hurt
Five lines, in the order they happen. The right column is why each line is there.
| # | Do this | Because |
|---|---|---|
| 1 | Generate the work list with code from the source of truth, never by typing or summarising it. | Removes the hand-typed, truncated and summarised corruption points in one step. |
| 2 | Count it, write the count and the list to a file, and pass the file path, not the list text, to the workers. | The count is the contract. A file survives context compaction; a message does not. |
| 3 | Give every worker an explicit slice by identifier, and have it echo the identifiers it received. | Turns a silent gap into a visible one before any work starts. |
| 4 | Reconcile completed identifiers against the original set before declaring the batch done. | The only check that catches an item that was never assigned. Success counts cannot. |
| 5 | Retry only the reconciled remainder, from the same file, never from a re-typed list. | A retry built from memory reintroduces the fault it was meant to fix. |
A retry is usually triggered by a worker failure, and the orchestrator rebuilds the retry list from what it remembers of the batch. That is a fourth hand-typed list, built under more pressure than the first. Items that were never assigned are still not in it, because the orchestrator never knew about them, and items that succeeded can be re-run because the model misremembers which slice failed. Retry the reconciled remainder from the file, or do not retry at all.
This is how we run our own multi-item batches, and the file with the count is the artefact we check first when a batch looks short. If you are building a pipeline that fans work out across agents and want the orchestration layer designed so that this class of gap cannot occur, that is part of what we do under AI transformation.
06 — ConclusionThe agents did what they were told; the list is what lied
Generate the list with code, keep the count, and refuse to say done until the set difference is empty
Parallel agents are reliable at the thing they are given. The unreliable step is the one before delegation, where a model writes down what exists, and that step belongs in code. Move the list, the count and the reconciliation out of the model's hands, pass identifiers instead of prose, and retry only from the file. The failure stops being silent, and most of the time it stops happening.