Home / Articles

Seven Silent Ways Context Pollution Breaks LangGraph Agents

Stale state, giant tool dumps, duplicate RAG chunks, lossy summaries and bloated toolsets: seven failures that raise no errors, with fixes and how to detect each.

Publisher: REACTAPP.TOP9 min read2174 words

This article is published in English.

Sources: 7 Ways Context Pollution Quietly Killed My LangGraph Agents

Picture a LangGraph agent that tells a user their project is "on track for July delivery." The calendar says August. The logs show no exception and no failed tool call, and nothing is red anywhere. By every metric the team tracks, the agent is healthy, and for three days it quietly misleads people before anyone catches on.

Incidents like this share one invisible cause, context pollution, and the seven cases below all trace back to it. Each produced zero errors. The scenarios are composites and illustrations, with company names and numbers made up, but the mechanics behind them are the kind agent builders run into regularly.

Context pollution in two minutes

When an agent reasons, it doesn't see your application. It sees one long block of text, the context window, and nothing else. Think of it as a desk: anything on the desk is usable, and anything off it doesn't exist for the agent, even if it sits in your database a few feet away.

Several things stack up on that desk each turn:

  • the system prompt, meaning the instructions
  • tool definitions, meaning what the agent may call
  • conversation history, meaning everything said so far
  • tool outputs, meaning whatever your APIs returned
  • state, which is what your LangGraph nodes stored and passed along
  • retrieved documents, if you use RAG

Beginners rarely hear this: the desk has a size limit, and attention isn't spread evenly across it. Content can be technically present and practically ignored. It can also be stale, duplicated or contradictory, and the model won't object. It reasons over the junk without comment.

Context pollution is wrong, stale, bloated or conflicting material sitting in the window and degrading behaviour without throwing a single error. That's the danger. A crash pages you at 2 a.m., while pollution just leaves your agent 20% wrong indefinitely.

Each case below gets a symptom, a root cause, a fix and a way to detect it in your own system, because a failure you can't detect will come back.

Case 1: the agent stuck in July

Symptom. Take a reporting agent for an invented utility, call it Meridian Energy. It kept quoting "this month's" numbers that actually belonged to the previous month. Users blamed the data pipeline, which was fine.

Root cause. At session start, a developer had stored the active reporting period in LangGraph state exactly once (a key named current_period holding 2026-07), and the checkpointer saved it. Users later resumed old sessions, a popular feature, and the saved checkpoint brought July back with it. The agent wasn't confused; it followed its context, and its context said July.

Fix. Adopt a rule that reshapes state design: never store what you can cheaply recompute. The current date, current period, anything labelled "today", should be calculated fresh at the start of each run, not persisted. Moving current_period out of checkpointed state and into a small node that recalculates it on every call costs one line of code and removes the whole class of bug.

Detection. In development, print the state dictionary at the start of every run and ask of each key whether it could be stale and whether you'd notice. Any key holding a date, a status or the word "current" is a suspect.

Case 2: an 8,000-token tool dump that drowned the instructions

Symptom. The agent began ignoring formatting rules. The system prompt said to open every answer with a summary table. It did, until it sometimes didn't. Randomly, which is the worst sort of bug.

Root cause. One tool called an API and put the raw JSON response into context. For small queries that was 400 tokens. For big ones it ballooned past 8,000 tokens of nested JSON full of IDs, metadata, null fields and pagination details that nobody needed. Landing mid-context, the dump turned careful instructions into a faint voice at the back of a noisy room. Attention went to the wall of JSON and the formatting rules effectively disappeared.

The unkind detail is that it only happened on large responses. Small queries worked, so connecting "agent misbehaves" to "user asked a big question" took weeks.

Fix. Tools should return facts, not dumps. Add a thin transformation layer inside each tool that pulls out the handful of fields the agent needs, shapes them compactly and discards the rest. One such tool dropped from about 8,000 tokens to about 300.

# Before: return response.json()          # 8,000 tokens of noise
# After:
def summarize_response(data: dict) -> dict:
    return {
        "project": data["name"],
        "status": data["status"],
        "owner": data["owner"]["displayName"],
        "due": data["dueDate"],
        "open_risks": len(data.get("risks", [])),
    }                                       # ~300 tokens of signal

Detection. Log the token count of every tool output. A tool that can return more tokens than your whole system prompt is a pollution source waiting for a large response.

Case 3: a correction that never replaced the original

Symptom. A user asks for the Northeast region, then immediately corrects themselves and asks for the Northwest. The agent answers for the Northwest, correctly. Four turns on, without being asked, it drifts back to the Northeast.

Root cause. Conversation history is append-only by default, so the mistaken instruction and the correction both stay in context permanently. Usually the model weights the newer message correctly, but usually isn't always, and as the chat grows the two versions blur into equally plausible facts. The agent wasn't recalling wrongly. It was recalling too much.

Fix. There are two options.

  1. Resolve, don't accumulate. On spotting a correction, don't just append it. Write the new value into a structured facts block in state (region set to Northwest) that the agent treats as authoritative, so the messy transcript doesn't have to be argued over again each turn.
  2. Edit the history. LangGraph lets you trim or rewrite messages before they re-enter context, so superseded instructions can simply be removed.

The broader lesson is that a conversation history is a log and not a knowledge base. Don't make the agent derive the truth from a transcript every turn.

Detection. Add a self-correction case to your evals: the user says X, then corrects to Y, then asks five more questions. If the agent ever slides back to X, you have this bug.

Case 4: RAG returned one answer five times and hid the real one

Symptom. People asked a question that the documentation plainly answered, and the agent produced a vague half-reply. The retrieval logs listed six fetched chunks, so retrieval seemed to be doing its job.

Root cause. The corpus held near-duplicates: one policy paragraph pasted into five different documents, as real enterprises often do. Similarity search worked perfectly and returned five almost identical chunks, which crowded out the one different chunk containing the real answer. Five seats at the table went to the same guest.

Fix. Deduplicate at retrieval time. Even a crude method works well: fetch 20 candidates, drop any chunk too similar to one already chosen and keep the top diverse set. If your vector store supports maximal marginal relevance, that's the same idea built in. Answer quality on policy questions improved at once with no change to model or prompt.

Detection. Log the retrieved chunks and read through them weekly. If one sentence regularly appears twice in a batch, you're paying for redundancy with relevance.

Case 5: the summary that dropped the one rule that mattered

Symptom. To keep long sessions affordable, a team added rolling summarisation: every N turns, older messages are compressed. Standard, widely recommended. Then an agent began putting draft records into official reports, even though the user had said "exclude drafts" eleven turns earlier.

Root cause. The summariser behaved like a summariser. It kept the storyline (the user wanted regional reports and talked about layout) and discarded what it ranked as minor. Yet "exclude drafts" wasn't minor. It was a constraint, and constraints can't be paraphrased: they either survive intact or vanish. Of all seven failures this one deserves the most worry, since summarisation looks like an unambiguous win in demos.

Fix. Separate memory into two lanes before any compression happens.

  • Narrative can be summarised aggressively.
  • Constraints, decisions and preferences are pulled into a structured list that never gets summarised. Entries are only added or explicitly revoked, and the whole list is injected into context on every turn.

The summary prompt can say so directly: before summarising, copy every instruction, constraint and decision into the constraints list verbatim.

Detection. In development, diff the constraint list before and after every summarisation run. A constraint that survives only inside a summary paragraph means the compressor is shredding your rules.

Case 6: a stack trace that made the agent distrust a working tool

Symptom. One tool timed out once, briefly, and worked on the very next call. Yet for the remainder of the session the agent kept telling users it was unable to reach the reporting system, even as it called that system successfully. Users trusted the sentence over the data, naturally.

Root cause. The full error trace, a TimeoutError after 30 seconds, was appended to the history and never left. To the model, "the reporting system is unreliable" became an established fact, and every later answer was tinted by it. One transient error turned into permanent pollution.

Fix. Treat errors as events and not as facts. After a successful retry, replace the error in history with a one-line note such as "(transient error, resolved on retry)". If a tool fails for good, give the agent a clean structured status and not a stack trace. Stack traces belong in logs, never in context.

Detection. Search live contexts for the strings Error, Traceback and Exception. Each match is either an ongoing incident or a leftover polluting later turns, and both should be cleaned out.

Case 7: twenty-five tools in one window

Symptom. Over several months the agent got slower and pricier, which was predictable as features piled on. It also began selecting the wrong tool for easy requests, such as returning a compliance export when someone wanted a project summary. Nothing was broken; everything had simply become noisier.

Root cause. The toolset had reached 25 tools, each with a long description and JSON schema, together using roughly 12,000 tokens before the user typed a word. Each turn the model weighed 25 options, many with overlapping descriptions like "get project data", "fetch project details" and "retrieve project info". Choosing a tool is a reasoning task, and the team had turned it into a multiple-choice exam with 25 similar answers.

Fix. Two parts.

  1. Prune aggressively. Merge tools that overlap, here shrinking 25 to 11, and rewrite each description around one question: when should the model choose this tool over its neighbours?
  2. Load tools by context. Not every node needs every tool. In LangGraph it's easy to bind only the relevant subset to each node, so a report-generation node might see four tools and not 25.

Token cost per turn fell by about a third, and wrong-tool picks nearly vanished.

Detection. Count the tokens in your tool definitions alone. If they exceed your system prompt and an average conversation combined, your agent is sitting an open-book exam where most pages are wrong.

What the seven have in common

Reread the seven and a single pattern emerges. No component was broken and nothing was missing. The pollution was consistently surplus, stale or repeated content.

That's why ordinary debugging fails here. Engineers are trained to hunt for absences: the missing null check, the unhandled exception. Context pollution needs the opposite skill, learning to look for what shouldn't be there.

If you keep one habit, make it reading your agent's raw context. Skip the logs and the traces dashboard and read the actual assembled text the model receives on a real production turn. It's the best-value hour available to anyone building agents, and almost nobody spends it.

A sixty-second checklist before you deploy

  1. Is any state value a date, a status or something called "current"? (Case 1)
  2. Could a tool return more tokens than the system prompt itself? (Case 2)
  3. When a user corrects themselves, can the old version ever win? (Case 3)
  4. Do retrieved chunks ever repeat each other? (Case 4)
  5. Can a constraint survive your summariser word for word? (Case 5)
  6. Do error traces stay in history after recovery? (Case 6)
  7. How many tokens do the tool definitions use before a user types anything? (Case 7)

Seven questions. Any answer of "probably, but unsure" is an incident waiting for a date.