Generated code is often good. The difficulty is that it looks identical whether it is right or wrong — the same confident tone, the same tidy formatting, the same explanatory comments.
These are the eight patterns worth learning to spot, with the check that catches each one.
1. Functions that do not exist#
The most disorienting one, because the code reads perfectly. A method appears with exactly the name you would have wished for, and it was never real.
text = "hello world"
print(text.titlecase()) # AttributeError — it is .title()This happens because these models predict plausible text, and a method named the obvious thing is highly plausible.
The check: if a method name is unfamiliar and suspiciously perfect, look it up in the official docs before running anything. Your editor’s autocomplete is a fast first filter — if it does not offer the method, be suspicious.
2. Code for a version you are not running#
Libraries rename things and remove them. Generated code often reflects a mixture of versions.
TypeError: __init__() got an unexpected keyword argument 'timeout'The check: when an argument is rejected or an import fails, check your installed version against the docs for that version specifically.
python -m pip show requestsTelling the assistant your version up front prevents most of these.
3. Only the happy path#
By far the most common problem, and the least visible — the code works when you test it and fails on real data.
def average(numbers):
return sum(numbers) / len(numbers) # ZeroDivisionError on []Empty inputs, missing keys, zero, negative numbers, network failures — generated code routinely assumes none of these happen.
The check: before running it, list what could be awkward and try each one.
print(average([2, 4])) # 3.0
print(average([])) # crash?
print(average([-2, 2])) # sensible?Asking “what edge cases does this miss?” about code you were just given is one of the highest-value prompts there is.
4. Security problems that look normal#
These are worth learning by sight, because they do not error — they just leave a hole.
# SQL built by joining strings
cursor.execute(f"SELECT * FROM users WHERE name = '{name}'") # injection
cursor.execute("SELECT * FROM users WHERE name = ?", (name,)) # safe// User text written as HTML
el.innerHTML = comment; // a script tag in the comment will run
el.textContent = comment; // safeAlso watch for hard-coded keys and passwords, eval() on anything from outside, and a bare except: that swallows every error including real bugs.
The check: scan for four things every time — string-built SQL, innerHTML with user data, credentials in the source, and eval.
5. More machinery than the problem needs#
Ask for something small and you may get a class hierarchy, a config object and a dependency.
class FileProcessorFactory:
...
# for something that reads one fileEvery extra layer is more to understand and maintain, and for a beginner it obscures what is actually happening.
The check: ask for it again with constraints — “rewrite this as simply as possible, standard library only, no classes”. Compare the two and keep the one you can explain.
6. Logic that is subtly wrong but passes the example#
The hardest to catch, because the sample call in the answer works.
def is_leap(year):
return year % 4 == 0 # correct for 2024, wrong for 1900The provided example was chosen to demonstrate the code, not to test it.
The check: test with values the answer did not use. Pick the awkward ones deliberately — boundaries, exceptions to the rule, the year 1900.
7. It does not match the rest of your project#
Different naming style, different error handling, a second HTTP library because it did not know you already had one.
Individually harmless; over a few months you have a codebase with three ways of doing everything.
The check: before pasting, compare against the file it is going into. Are the names in the same style? Are errors handled the same way? Does it import something you already have an equivalent of?
8. Invented specifics#
Ask about a product, an API’s fields, prices or benchmark numbers and you may get precise-sounding values that were never checked.
This matters most with API response shapes, because the code is built around field names that may not exist.
The check: anything factual and specific — a field name, a version number, a limit, a price — gets verified against the source before you depend on it. Log the real response rather than trusting a documented one.
A two-minute review#
Before code you did not write goes into your project:
- Can you explain every line? Any line you cannot explain, you cannot debug later.
- Does it answer what you asked? Not a nearby, easier question.
- Do the functions exist? Check anything unfamiliar.
- What happens with empty, zero and missing? Actually run those.
- Any of the four security patterns?
- Is it more complicated than the problem?
- Does it fit the code around it?
Two minutes. It catches nearly everything on this page.
When to stop and write it yourself#
- Three rounds and it still does not work — you have probably misdiagnosed the problem, and more attempts will not find that
- It uses something unfamiliar for a task that sounds simple
- It is much longer than you expected
- You cannot explain it and it is going somewhere that matters
Writing your own version, even a worse one, is often faster than debugging code you did not write and do not understand.
Questions people ask#
Does this mean I should not use AI for code?
No. It means review it like you would a stranger’s pull request. Used well it is genuinely useful — see how to use AI to learn programming.
Why does it sound so confident when it is wrong?
Confidence is not a signal these systems produce from certainty — the tone is the same either way. Treat fluency as telling you nothing about correctness.
Are newer models better at this?
Broadly yes, and the failure patterns are the same ones, just less frequent. The review habit stays worth having regardless.
Who is responsible if generated code causes a problem?
Whoever committed it. “The tool wrote it” has never been a defence for anything that ships.
Where to go next#
- How to check AI-generated code — the full review checklist
- How to ask AI better programming questions
- How to read programming errors