Fighting the Prior: When the Model Knows a Wrong Version of Your Stack
There's a specific kind of argument you can only have with a language model. You paste in your code. It rewrites a working call into one that hasn't existed since a major version ago. You correct it. It apologizes, agrees with you, and on the next turn does the exact same thing. You are not fighting ignorance. You are fighting a confident, well-rehearsed memory of a different version of your stack — and that memory was reinforced by more training examples than your correction will ever carry.
This is the failure mode I've come to think of as fighting the prior. The model's parametric knowledge — everything it absorbed during training — contains the popular, the outdated, or simply the different version of the framework you're actually using. When your context and its prior disagree, the prior often wins. And unlike a plain hallucination, this one is dangerous precisely because it's plausible: the deprecated API used to be correct, so the code looks right, passes a casual read, and sometimes even compiles.
The reason this feels different from ordinary model error is that it's structural, not random. A hallucinated function name is noise you can catch. A confidently deprecated API is signal — the model has learned the wrong thing well. The tokens for the old call carry higher probability than the tokens for the new one, because the old call appeared thousands of times in the training corpus and the new one appeared a handful. You're not asking the model to guess; you're asking it to overrule its own most-reinforced pattern on the strength of a few lines you pasted in. That's a much harder request than it looks.
Why the prior beats your context
Start with the arithmetic of the training set. When researchers measured how often code models reach for deprecated APIs, they found something telling: in the source repositories these models learn from, deprecated and replacement calls coexist, with replacements outnumbering deprecated usages only about two to one. That's not a clean signal. Roughly a third of the relevant examples the model saw were the old way of doing things. The imbalance isn't enough to teach the new idiom decisively, but it's more than enough to keep the old one alive as a high-probability path.
The result shows up in the numbers. Across a range of code models, the deprecated usage rate — how often the model emits an obsolete API when it should have used the replacement — lands in the 25–38% range overall. But the headline number hides the real danger. When the surrounding code already looks a little dated, the deprecated usage rate climbs to 70–90%. The model reads the neighborhood and matches it. Give it up-to-date context and the rate drops to 9–18%. In other words, the prior is contextual: the model is constantly inferring "which era of this library am I in?" from cues you may not even realize you're sending.
Now layer on the knowledge-conflict research, which asks the sharper question: what happens when the model's memory and the documentation you hand it directly contradict each other? Left to its own devices — no docs in context — models correctly adopt a post-cutoff API change only about 75% of the time, and the code actually runs only 43% of the time. The failure modes are specific and worth naming: complete omission of the update (the model just ignores it), reversion to the deprecated call after initially accepting the change, and — most striking — hallucinating a brand-new function when told a new API exists, rather than admitting it doesn't know the real one. The model would rather invent a plausible member than say "that's outside what I learned."
This is the core asymmetry to internalize: your context is competing with the model's prior, and the prior is not a blank slate you're writing onto — it's an incumbent you're trying to unseat. Everything downstream follows from taking that framing seriously.
Why generic evals never see it
Here's what makes this failure mode so persistent: it is nearly invisible in the evaluations most teams actually run. Standard coding benchmarks test the model against problems whose correct answers are what the model already believes. They reward the prior. A model that confidently writes the popular, widely-documented version of an API scores beautifully on a benchmark built from that same popular corpus. The eval and the training set share a worldview, so the conflict never arises.
The conflict only surfaces where your stack diverges from the internet's median stack — and by definition, that divergence is specific to you. You're on a major version the training data barely saw. You maintain an internal fork with renamed methods. You have a house convention that looks like a mistake to anyone who learned the framework from public tutorials. None of that is in a public benchmark, because a public benchmark is built from exactly the median the model already overfit to.
So the model looks excellent in every generic measurement and quietly sabotages your actual codebase. The gap between "great on benchmarks" and "wrong in my repo" isn't a quality problem you can fix by picking a smarter model. A more capable model often holds its wrong prior more firmly, because capability and confidence rise together. The gap is a measurement problem: you're evaluating the model on the world's code instead of yours.
Which means the first practical move isn't a prompt tweak. It's building a small, adversarial eval out of your divergences — the specific APIs, config keys, and patterns where your stack and the model's prior part ways — and running new models against it before you trust them. This is the one eval that will never come from a vendor, because it's a map of where your reality contradicts theirs.
Detection: probing for prior-versus-context conflict
Before you can fix the conflict, you have to see it, and "see it" here means something more targeted than eyeballing diffs. You want probes designed to provoke the disagreement so you can measure which side the model lands on.
The cleanest probe is a controlled A/B. Take a task that touches one of your divergent APIs. Run it twice: once with only the task, once with the authoritative snippet or doc pasted into context. If the outputs differ — if the model writes the old idiom bare and the new one when shown the docs — you've found a live conflict, and you've also confirmed that context can move it, which not every conflict allows. If the outputs are identical and both wrong, the prior is winning even against direct evidence, and you're in the harder regime.
A few practical signatures to watch for, because each points at a different remedy:
- Silent reversion. The model uses your corrected API on turn one, then drifts back to the deprecated one a few turns later as the correction falls out of the effective context. This is a memory-decay problem, not a comprehension problem.
- Plausible invention. You tell the model a new method exists; it fabricates a signature rather than asking or refusing. This means it trusts its generative prior over the gap in its knowledge — a calibration failure.
- Neighborhood matching. The model's choice flips depending on how modern the surrounding code looks. Dated imports at the top of the file pull everything below them toward the old idiom.
- The confident correction. The model "fixes" your intentional, unusual pattern back into the common one, treating your deliberate choice as a bug. This is the prior asserting itself as a style authority.
Log these. A conflict you've named is a conflict you can build a regression test around; a conflict you only vaguely sense will resurface every time you upgrade the model.
Countermeasures that actually hold
Now the useful part: what works, ranked roughly by durability, because several popular fixes are weaker than they look.
Negative instructions decay. The instinct is to write "do not use the deprecated foo() method." This helps least and fades fastest. Prohibitions are brittle: they consume attention, they don't tell the model what to do instead, and they lose force as the conversation lengthens and the instruction slides toward the back of the context. Telling a model not to think of the popular API is about as effective as telling a person not to think of an elephant. Every "don't use X" is also a reminder that X exists.
In-context authoritative docs win — when they're structured. The single largest lever in the research is putting the current API specification directly in context. Doing so lifted correct-adoption rates from roughly 75% to 93%, and more than doubled the rate at which the generated code actually ran. This is why the llms.txt convention and per-dependency doc injection have caught on: the fix for a wrong prior is a stronger, closer, more authoritative source of truth than the prior. But note the qualifier — structured. A dumped changelog buried in a wall of text underperforms a tight, canonical snippet placed near the point of use. Proximity and clarity matter as much as presence.
Turn generation into verification. One of the most effective single techniques is self-reflection: after the model drafts code, prompt it to check its own output against the provided docs before finalizing. This converts a generation task — where the prior dominates — into a verification task — where the evidence in front of it dominates. The measured gains were meaningful, especially for the hardest case of modified (not merely added) APIs. Generation leans on memory; checking leans on what's actually on the page.
When in doubt, rename the collision away. The most underrated fix is the least clever one. If your internal API keeps getting "corrected" into someone else's idiom because the names collide with a popular library the model has memorized, sometimes the cheapest durable fix is to stop colliding. Rename your internal helper so it no longer overlaps with the model's strong prior for a different Client or parse() or connect(). You're not going to win a probability fight against a name the model saw ten thousand times. Move your name out of the blast radius and the conflict simply evaporates — no prompt engineering required.
Freshen the neighborhood. Because the model reads context to decide which era it's in, keep the surrounding code current. Modern imports, up-to-date call sites, and a clean file top all bias generation toward the new idiom for free. If you're working in a file full of legacy calls, expect the model to match them, and pull an authoritative example into view to reset the reference frame.
The upgrade you can't see coming
The uncomfortable implication is that this problem doesn't go away with the next model release — it moves. Every new model has a new cutoff, which means a new set of things it confidently knows and a new set it confidently misremembers. The library you're on might be well-represented in the next model's training data and poorly represented in the one after. Your carefully tuned "use the new API" scaffolding might become unnecessary, then necessary again, then wrong in a new way, all without any change on your end.
That's why the durable investment isn't any single prompt. It's the harness: the small adversarial eval that maps where your stack diverges from the median, the probes that detect which side of a conflict the model lands on, and the doc-injection plumbing that keeps authoritative sources closer than the prior. Treat the model's memory as an incumbent you're perpetually running against — sometimes an ally, sometimes an opponent, never neutral. The teams that ship reliably with these tools aren't the ones with the best prompts. They're the ones who stopped assuming the model was a blank slate and started engineering for the fact that it walked in already believing something.
- https://arxiv.org/html/2406.09834v3
- https://arxiv.org/html/2604.09515v1
- https://arxiv.org/abs/2606.20245
- https://arxiv.org/html/2506.06485v3
- https://arxiv.org/html/2511.21022
- https://www.promptfoo.dev/docs/guides/prevent-llm-hallucinations/
- https://dev.to/toyama0919/using-llmstxt-with-cursor-and-claude-code-a-concrete-playbook-4jln
