
Drew Breunig wrote an essay in June 2025 called How Long Contexts Fail that gave names to four distinct ways an LLM’s context goes bad: poisoning, distraction, confusion, and clash. When I first read it, it landed as a tidy taxonomy, the kind of thing that is satisfying to read and easy to forget. Then I went back through a year of bugs in Context Hub, my cross-session memory layer, and Multicast, my MCP gateway, and realized I had not read a taxonomy. I had read a list of my own production incidents, with the root causes I had paid for one at a time.
So this is the build-log version. Four failure modes, four real bugs I shipped, what each one actually cost, and the structural fix that made it stop. If you are building anything that decides what a model sees, a memory layer, a RAG pipeline, an agent loop, you will hit all four. Here is the map so you can recognize them faster than I did.
A quick framing before the bugs. The reason these four exist as distinct modes and not one blurry “context bad” bucket is that they fail at different layers of the system. Poisoning is a data-integrity failure. Distraction is an accumulation failure. Confusion is a selection failure. Clash is a versioning failure. Naming which layer broke is most of the fix, because it tells you where to put the guardrail. That is the whole value of the taxonomy: it turns “the agent is acting weird” into “the agent is acting weird because of X,” and X has an address.

Failure 1: Poisoning, the hallucination that moved into the house
The mode: a hallucination or error gets written into the context once, then gets referenced on every subsequent turn as if it were ground truth. The model cannot tell its own past guess from a fact, so it builds on the poison and compounds it.
The bug I shipped: early Context Hub would persist whatever the model concluded about a session, including the conclusions that were wrong. In one case a session inferred a project detail incorrectly, the inference got saved to memory, and from then on every new session opened with that wrong detail injected as established context. The model never re-derived it because why would it, it was right there in memory, stated as fact. The wrong belief had moved in and was paying no rent. It took me an embarrassingly long time to notice, because each individual session looked internally consistent. The error was upstream of the conversation.
The root cause: I had no provenance on stored memories. A fact the user stated and a fact the model guessed went into the same store with the same authority. Once written, both read back as truth.
The fix: separate trusted context from derived context, and never let derived context read back as ground truth. A memory layer that cannot tell what it knows from what it guessed will poison itself, and the poison is permanent until you go in and evict it by hand. Now anything the model concludes is tagged as derived, carries lower priority on retrieval, and gets re-validated rather than asserted. The structural rule: provenance is not a nice-to-have on a memory system, it is the thing that stops a single hallucination from becoming a permanent resident.
Failure 2: Distraction, the agent that reads its own diary instead of working
The mode: the context grows so long that the model over-focuses on the accumulated history and stops synthesizing new plans, just recombining old ones. The window is full of the agent’s own past, and it cannot see past it.
The bug I shipped: the default agent loop that appends everything. Every tool call, every observation, every intermediate thought, carried forward to the next turn forever. By turn 25 or 30, the agent was reasoning over a transcript thick with its own abandoned attempts, and it started looping, re-proposing plans it had already tried and discarded, because those discarded plans were the loudest thing in the window. Google’s own Gemini agent work documented the same thing: past around 100K tokens of history, the agent favored repeating actions from its history over generating fresh ones. I watched my own agent do it before I knew it had a name.
The root cause: accumulation as the default. I treated history as free to keep, on the storage mental model, when every retained turn is a distractor competing for attention.
The fix: active pruning, not retention. The research is blunt here: in code-editing agents, just masking old observations or summarizing them away cut cost by more than half with no loss in solve rate, and sometimes the pruned agent beat the one that kept everything. The most recent, relevant context is usually sufficient. The full trajectory is usually a liability you are paying interest on. Context Hub now condenses old turns aggressively instead of carrying them raw, and the agent got measurably less stuck.
Failure 3: Confusion, fifty tools and the wrong one chosen
The mode: superfluous-but-plausible content in the window degrades the output, not because any of it is wrong, but because the volume makes it harder for the model to discriminate. The classic version: too many tools loaded, and the model picks badly from a menu it can read perfectly.
The bug I shipped: this one is native to a gateway. Multicast’s whole job is to expose many MCP servers’ tools through one surface, which means it is structurally a confusion machine if you are not careful. Wire up enough servers and the model sees a long menu of tools, many with near-identical descriptions, and starts mis-selecting, calling the search tool when it wanted the fetch tool, calling a tool from the wrong server entirely. Nothing in the context was incorrect. There was just too much of it, too similar, and the model’s ability to discriminate degraded with the length of the menu.
The root cause: I exposed everything because I could, on the same “more is safe” instinct. A 50-tool surface is not 50 capabilities. It is one selection problem with 50 distractors.
The fix: scope the tool surface to the task, do not expose the union of everything. The number of tools a model can choose well from is far smaller than the number it can technically see, and the gap between those two numbers is pure confusion. Multicast now favors narrow, task-scoped tool sets over the full catalog, and tool descriptions are written to be maximally distinct from each other rather than individually thorough. Distinctness beats completeness when the failure mode is selection.
Failure 4: Clash, when v1 and v2 of the truth are both in the window
The mode: two parts of the context directly contradict each other, an early statement and a later correction, two tools returning inconsistent results, and the model has to reconcile them. Often it picks the wrong one, frequently the earlier, more-wrong one, because it got established first.
The bug I shipped: the meanest variant, and it came from the layer underneath. In Context Hub I once had a memory get updated, but a stale copy of the old value was still being retrieved from a different path. The model received both the old and the new value of the same fact in one context and had to guess which was current. It guessed wrong often enough to be a real problem, and the bug was invisible from inside any single response because the contradiction was the input, not the output. This is the same class of pain as a stale cache, except the “cache” is the model’s working memory and the cost is a wrong action, not a wrong render.
The root cause: no single source of truth for a given fact at retrieval time. Two paths could surface two versions, and nothing reconciled them before they hit the window.
The fix: reconcile before you inject, never after. If two versions of the same fact can reach the context, the model will arbitrate between them, and the model is the worst possible place to put that decision. Context Hub now dedupes and resolves to the current version before assembly, so the model never sees the contradiction. The principle generalizes: contradiction is a context-assembly bug, and the fix belongs in assembly, upstream of the model, not in a prompt begging the model to “use the most recent information.”
The reality check
I want to be honest about the limits of this map. Naming the four modes did not make my systems correct, it made my debugging faster. When an agent acts weird now, I run the checklist, is this poisoning (bad data got in), distraction (too much history), confusion (too many similar options), or clash (contradictory versions), and it almost always collapses to one of the four with an address I can go fix. That is worth a lot. But the modes overlap and compound in real systems, a poisoned fact also becomes a clash once you correct it but leave the old copy around, and untangling which one you are looking at is still judgment, not a flowchart.
And all four share one root I keep relearning: they are downstream of treating context as free to fill. Poisoning is keeping data you should have validated. Distraction is keeping history you should have pruned. Confusion is exposing options you should have scoped. Clash is keeping versions you should have reconciled. Every one of them is a failure to decide what not to include. That is the discipline, and it is unglamorous: most of building a good memory layer is building good ways to leave things out.
I am reworking both systems around assembly-time guardrails for each mode, provenance for poisoning, pruning for distraction, scoping for confusion, reconciliation for clash, and I will report what the failure rate looked like before and after once I have run it long enough to trust the numbers. If you have shipped a memory or agent layer: which of the four bit you hardest? I am collecting war stories, because I suspect the distribution is not even, and I would bet most people’s worst one is clash.


