AI Slop Has a Shape
A field taxonomy of AI slop in code — duplicated helpers, phantom dependencies, defensive boilerplate, and almost-right logic — with how to spot and prevent each.
“Slop” is the word the industry settled on, and it’s a good one. It captures the specific texture of low-effort machine output: not wrong, exactly, but loose, padded, and indifferent to the system it lands in. In prose, slop is the six-paragraph email that should have been two lines. In code, it’s harder to see, because it compiles. It passes the tests you happened to write. It looks, at a glance, like the thing a competent engineer would have produced.
But AI slop in code has a shape. Once you learn to recognize the silhouette, you see it everywhere — in pull requests, in the codebase you inherited, in your own work on a tired afternoon when you accepted three suggestions in a row without reading them carefully. The patterns are not random. They fall out of how language models generate code: locally, token by token, optimizing for a plausible continuation rather than for the health of the whole. Understanding why a model produces each kind of slop is the fastest route to spotting it and to building review habits that catch it.
This is a field guide. Seven patterns, each with its mechanism, its tell in review, and its fix. None of these are arguments against AI-assisted development — the productivity is real and the tooling keeps improving. They’re arguments for reading what the machine writes the way you’d read a junior engineer’s first draft: generously, but closely.
The data says the texture is changing
Before the taxonomy, the macro signal. GitClear analyzed 211 million changed lines of code from January 2020 through December 2024 and found that the shape of the average commit is shifting in a measurable direction. Copy-pasted lines rose from 8.3% to 12.3% over the period, while “moved” lines — GitClear’s proxy for refactoring, where existing code is relocated and reused rather than re-typed — fell from roughly a quarter of changed lines in 2021 to under 10% in 2024. For the first time in GitClear’s data, copy-pasted code surpassed moved code, and the report’s headline frames it as 4x growth in code clones.
You can quibble with any single metric, but the trend is coherent and it matches what the tools encourage. AI assistants make it trivially easy to insert a fresh block of code. They make it much harder — because of limited context and the absence of any incentive to look — to notice that a nearly identical block already exists three files over. The path of least resistance is duplication, and the data shows the industry walking down it.
That macro pattern decomposes into specific, recognizable micro-patterns. Here they are.
Pattern 1: The duplicated near-identical helper
This is the master slop pattern, the one GitClear is measuring at scale. You ask for a function to format a currency value. You already have formatCurrency in utils/money.ts, but the model can’t see it, or doesn’t bother, so it writes formatMoney in the component file. Six months later you have formatCurrency, formatMoney, displayPrice, and toCurrencyString, three of which round differently, one of which doesn’t handle negative numbers, and all of which are “right” in isolation.
Why AI produces it. A language model generates the most plausible code for the prompt in front of it. It has no durable model of your codebase and no drive to search for prior art. Reuse requires knowing what already exists; generation requires only knowing what’s typical. Typical is cheaper.
How to spot it in review. Watch for new utility functions whose names are synonyms of existing ones. Watch for logic that feels like something you’ve already reviewed. A duplication-detection tool in CI is the reliable catch here — humans are bad at remembering that a near-twin exists in another directory.
How to fix it. This is the Don’t Repeat Yourself principle, and it’s worth restating in its original form. Andy Hunt and Dave Thomas, in The Pragmatic Programmer, defined DRY as: “Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.” The fix is to delete the duplicate and route every caller through the one canonical version. The harder, more valuable habit is to prompt for reuse explicitly — “use the existing currency formatter” — and to give the model the relevant file in context so it has something to reuse.
Pattern 2: Needless abstraction layers
The inverse failure. Instead of duplicating, the model over-engineers: a UserServiceFactoryProvider to instantiate the one user service the app will ever have, an interface with a single implementation, a generic <T> wrapper around a function called in exactly one place. The code reads as “enterprise,” which is precisely the problem — it has absorbed the surface style of large codebases without the conditions that justified the structure.
Why AI produces it. Training data is full of heavily abstracted code from large, mature projects where the abstraction earned its keep. The model reproduces the patterns it has seen most, regardless of whether your fifty-line script needs a dependency-injection container. Plausibility, again, not appropriateness.
How to spot it in review. Count the implementations behind each interface. Count the call sites for each generic. If an abstraction has one of each and no concrete plan for more, it’s speculative. Ask: what future requirement is this serving, and is that requirement real or imagined?
How to fix it. Inline it. The cheapest abstraction to add later is the one you didn’t build prematurely. Collapse single-implementation interfaces into their concrete class; flatten factories that produce one thing. You can always introduce the seam when a second case actually arrives — and you’ll design it better with two real examples than with zero.
Pattern 3: Over-defensive boilerplate
Every function arrives wrapped in a try/catch that swallows the error and logs a string. Every parameter gets a null check, a type check, and a length check before anything happens. Inputs that cannot occur given the call sites are guarded anyway. The function is three lines of logic inside twenty lines of armor.
Why AI produces it. Defensiveness is a safe default for a generator that doesn’t know your invariants. It can’t see that this internal function is only ever called with validated input, so it guards everything. And defensive code is well represented in training data because tutorials teach it. The model is hedging on your behalf, indiscriminately.
How to spot it in review. Look for validation that duplicates guarantees already enforced upstream. Look for catch blocks that catch, log, and continue — swallowing failures that should propagate. Look for null checks on values the type system already proves non-null.
How to fix it. Push validation to the boundary — validate once where untrusted input enters the system, and trust your types and invariants inside. Let errors you can’t handle propagate to a layer that can. A function that can’t meaningfully recover from an exception should not be catching it. Defensive code that hides failures is worse than no defense, because it converts loud bugs into silent ones.
Pattern 4: Phantom dependencies and hallucinated APIs
The model imports a package that doesn’t exist. It calls a method that was never on that object. It passes a config option the library has never supported. The code is internally consistent and entirely fictional.
This one has graduated from annoyance to security threat, and it has a name: slopsquatting. The mechanism: a peer-reviewed analysis of package hallucination, “We Have a Package for You!”, tested 16 LLMs across 576,000 generated code samples and found that 19.7% of recommended packages did not exist. Open-source models hallucinated far more (21.7% on average) than commercial ones (5.2%). Across the runs, the researchers catalogued 205,474 unique hallucinated package names.
The dangerous part is that the hallucinations are repeatable. A majority recurred across multiple runs rather than appearing as one-off noise. That predictability is the attack surface: a malicious actor can ask a popular model what it tends to hallucinate, register those names on the package registry with a payload inside, and wait for the next developer to paste in a confident pip install of a package that, until last week, did not exist.
How to spot it in review. Treat any unfamiliar import as guilty until verified. Check it against the actual registry, not against the model’s confidence. Check that the method exists in the installed version’s documentation, not just that the call looks right.
How to fix it. Lockfiles, an allowlist of approved dependencies, and a CI step that fails the build on any package not already vetted. Pin versions. Never let a generated install command run unreviewed. This is one of the clearest cases where AI output needs a hard gate, not a soft glance — the kind of automated check we cover in our AI code quality gate guide.
See how developers track their AI coding
Explore LobsterOnePattern 5: Verbose comments that restate the code
// increment the counter by one
counter = counter + 1;
// loop over each user in the users array
for (const user of users) { ... }
The comments add nothing a reader couldn’t get from the line below. Worse, they’re the comments most likely to rot — they describe the what, which the code already says, instead of the why, which the code can’t.
Why AI produces it. Models are rewarded, implicitly, for output that looks thorough and well-documented. Restating a line in English is the easiest way to manufacture the appearance of care. It costs the model nothing and looks diligent. It is the code equivalent of padding an essay to hit a word count.
How to spot it in review. If deleting the comment loses no information, the comment is slop. Good comments explain intent, trade-offs, constraints, and the surprising — “this looks redundant but the API double-fires,” “magic number from the vendor spec, do not change.” Comments that narrate syntax are filler.
How to fix it. Delete the narration. Keep the comments that explain why. If a block needs a comment to explain what it does, that’s usually a sign the code should be clearer — a better name, a smaller function — not that it needs annotation.
Pattern 6: Copy-paste proliferation
Distinct from Pattern 1’s accidental near-twins, this is the same block pasted deliberately and tweaked in place — five API handlers that are 90% identical with one different field each, a switch statement with eight cases that vary by a single string. The model produces it because you asked for “the same thing but for orders,” and the cheapest plausible answer is the previous block with the nouns swapped.
This is the behavior most directly responsible for the duplication trend in the GitClear data, and it compounds. Each pasted copy is a place a future bug fix has to be applied, and a place it can be forgotten. Short-term churn — code written and then rewritten within a couple of weeks — climbs alongside it, because duplicated code is code nobody fully owns.
How to spot it in review. Diff the new blocks against each other, not just against the old code. If three functions differ only in a literal or two, they want to be one function with a parameter. Structural duplication detection in CI catches what eyes miss across files.
How to fix it. Extract the shared shape into one function, table, or configuration, parameterized by what actually varies. This is the “moved” operation GitClear is watching decline — the refactor that turns five copies into one definition. Doing it deliberately, as part of accepting AI output rather than after the fact, is one of the highest-leverage habits in AI-assisted work.
Pattern 7: “Almost right” logic
The most dangerous pattern, because it’s the one that survives review. The off-by-one in the boundary condition. The pagination that drops the last page. The retry that doesn’t back off. The date math that’s correct except across a daylight-saving boundary. The code reads correctly. It probably even runs correctly on the happy path you tested. It’s wrong in the place you didn’t look.
This is not a fringe complaint — it is the single most-cited frustration in the field. In the 2025 Stack Overflow Developer Survey, 66% of developers named “AI solutions that are almost right, but not quite” as their top frustration with AI tools, and 45.2% said debugging AI-generated code is more time-consuming than they expected. The same survey found that more developers distrust the accuracy of AI tools (46%) than trust it (33%). The “almost” is doing enormous damage, precisely because it slips past the glance.
Why AI produces it. A model optimizes for plausible continuation, and “almost right” is what maximally-plausible-but-not-verified looks like. The model has no execution feedback at generation time; it has never run the function. It produces the code that looks like correct code, which is exactly the code that fails the edge case while passing the eye test.
How to spot it in review. You can’t spot “almost right” by reading for plausibility — plausibility is the trap. You spot it by reading for the specific failure: the empty input, the single-element list, the boundary value, the timezone, the concurrent write, the integer that overflows. Adversarial reading, not sympathetic reading.
How to fix it. Tests that target edge cases, not the happy path the model already nailed. Property-based tests where they fit. And a discipline of treating generated logic as unverified until you’ve personally traced the boundary conditions. The cost of “almost right” is paid in production, by someone debugging at 2 a.m., unless it’s paid in review by someone reading adversarially. The doom-loop dynamic — re-prompting the model to fix its own almost-right output and getting a different almost-right answer — is its own trap, one we dig into in preventing AI coding doom loops.
Why review habits beat heroics
The thread connecting all seven patterns is that none of them are caught by asking “does this look like good code?” They’re caught by asking sharper questions: Does this duplicate something? Does this abstraction earn its keep? Does this package exist? Does this handle the empty case? Slop is engineered to pass the lazy version of review and fail the rigorous one.
That has two implications. First, the review bar has to rise as AI authorship rises — the assumption that a human wrote each line carefully, and so it deserves a sympathetic skim, no longer holds. We’ve written about what that looks like in AI coding code review practices. Second, the patterns that resist eyeballing — duplication across files, phantom dependencies, missing edge-case coverage — belong in automated gates, not in the reviewer’s working memory. CI never gets tired on a Friday afternoon.
It also helps to know whether your team is trending toward slop or away from it. Rising duplication, falling refactor ratios, and churn spikes are measurable signals, the kind of leading indicators that tell you a habit is forming before it becomes a liability in production. The point isn’t to police individuals — it’s to make the texture of the codebase visible while it’s still cheap to change.
The Takeaway
AI slop isn’t a vague vibe. It’s a finite set of recognizable patterns, each one a direct consequence of how a generator works: locally, plausibly, without memory of your system or feedback from running your code. Duplicated helpers and copy-paste proliferation come from a model that can’t see what already exists. Needless abstraction and over-defensive boilerplate come from a model imitating the surface of code it can’t contextualize. Phantom dependencies come from a model that confuses plausible with real — and slopsquatting turns that confusion into a supply-chain attack. Verbose comments come from a model performing diligence. And “almost right” logic comes from a model that has never executed a single line it wrote.
The fix is not to stop using these tools. It’s to read what they produce with the specific suspicion each pattern deserves, to push the mechanical checks into automation, and to treat reuse and edge-case verification as part of the act of accepting a suggestion — not as cleanup for later. Generation is cheap now. Judgment is the thing you still have to bring. Slop is what happens when you forget that, one accepted suggestion at a time. Recognizing the shape is most of the defense.
Pierre Sauvignon
Founder
Founder of LobsterOne. Building tools that make AI-assisted development visible, measurable, and fun.
Related Articles

Code Review Best Practices for AI-Generated Code
How code review changes when the author is an AI — what to look for, common failure patterns, and a review checklist for AI-assisted development.

How to Prevent AI Coding Doom Loops in Production Codebases
What doom loops are, how to detect them in your codebase, and the metrics-driven approach to breaking the cycle before it compounds.

AI Code CI/CD Gating: A Decision Tree for Blocking, Flagging, and Passing
When to block an AI-generated commit at merge, when to flag it for extra review, and when to let it through. A concrete gating tree for staff engineers responsible for production safety.