Code Smells in AI-Generated Code: 7 Signals to Stop and Rewrite
AI-written code that runs isn't necessarily good code. This guide covers 7 smells specific to generated code — defensive overkill, apologetic comments, ghost abstractions, and more — each with detection tips and fixes, so you catch them before they fossilize.

Running and well-written are two different things
AI-generated code has a signature trait: it looks fine on first read and becomes a minefield in three months. AI optimizes for "passing right now," not "maintainable long-term." The 7 smells below are the most common in AI code — smell any of them and it's worth stopping to fix. Earlier is cheaper.
1. Defensive overkill: try/catch as cure-all
AI loves wrapping every function in try/catch, then just logging inside the catch. Result: errors get swallowed, and when production breaks you can't even find a stack trace. Fix: delete the "just in case" catches; handle exceptions centrally at boundaries (API entry points, queue consumers).
2. Apologetic comments: code explaining why it's bad
"Using a trick here, temporary" / "TODO: optimize later" — when AI writes comments like these, it knows the code is questionable and chose to paper over it. Don't let them slide: fix it now or convert it into a tracked issue. A TODO in a comment that survives a week is effectively permanent.
3. Ghost abstractions: 'generic' designs used exactly once
AI loves premature abstraction: an interface with one implementation, a factory called from one place, ten config fields reserved "for the future." YAGNI applies hard here: delete every abstraction with no second use case today; add it back when actually needed — when you'll understand the requirements better anyway.
4. Copy-paste variants: three functions 90% identical
Ask AI to "write a similar one" and the laziest move is duplicating with two lines changed. In three months a logic change means editing three places — and you'll miss one. Fix: extract a parameterized single function, or at least have AI run a "duplication check" on its own output.
5. Type gymnastics: the great any escape in TypeScript
Faced with complex types, AI's first instinct is as any — "make it run first." Once any gets in, the type system goes blind there and all future refactors rely on eyeballs. Fix: treat any as a compile error — every any needs a comment explaining why it's temporarily bypassed and when the real type lands.
6. Config explosion: the env file is longer than the code
AI tends to make everything configurable: thresholds, flags, strategies all stuffed into environment variables. At deploy time nobody knows which are required or what the defaults are. Fix: separate "only known at deploy time" (secrets, URLs) from "fine as constants" (retry counts, timeouts) — hardcode the latter.
7. Theatrical tests: assertTrue(true)
The most dangerous one. AI-written tests often cover only the happy path, assert vaguely, or mock the very thing under test — all green, all wrong. Fix: for every PR, make AI answer three questions — what does this test verify? If I break the implementation, does the test go red? Are edge cases covered? Can't answer? Rewrite the tests.
The one-line summary
AI writes code 10x your speed — and manufactures technical debt at 10x too. Build the habit: every time AI hands you code, scan this list. Five minutes now saves a lost weekend three months later.
Related articles

Prompts in vibe projects live in code strings, admin text boxes, and docs — changed live, version unknown when things break. This guide shows how to treat prompts like code: a prompts/ layout, YAML frontmatter, semantic versioning, PR reviews, canary rollouts with one-click rollback, plus an evals baseline — and a real war story: one added sentence cost 12 points of classification accuracy.

The faster AI writes code, the more review matters. Four layers: diffs for logic (boundaries, errors, concurrency — plus auth, payments, SQL, encryption, secrets), runtime for behavior (type checks, lint, security scans go green first), AI for first-pass screening (a second model reviews, humans read only flagged parts), humans for the final call (AI never clicks merge). Includes commit norms, PR template, branch protection, rollback plans.

Cloudflare's Birthday Week blog makes the case plainly: GitHub was designed for humans writing code; the agent era needs the collaboration layer reinvented. Artifacts enters open beta with a repo for every agent, plus a developer competition — $25,000 in credits for first place, deadline October 14. This is the first time a major infra vendor has put 'infrastructure for agents writing code' on the table as a public proposition.