Reduce Hallucinations in AI-Generated Code: A Review Checklist
Spot and fix AI code hallucinations before they ship with a five-point review checklist that catches invented APIs, fake imports, and confident wrong answers.
AI coding tools are extraordinarily good at sounding confident. When they generate code that looks plausible but does not work, the model is not lying. It is hallucinating: producing output that matches the statistical patterns of correct code without implementing a correct solution.
A 2024 study found ChatGPT answered 52% of Stack Overflow questions incorrectly, delivering wrong answers with confident-sounding phrasing (source: Communications of the ACM). For generated code, the stakes are higher — a hallucinated function call compiles fine but silently corrupts data until production.
What does an AI code hallucination look like?
Hallucinations fall into recognisable patterns. Once you know what to look for, you start seeing them in almost every long AI-coding session.
| Type | Example | Why it looks real |
|---|---|---|
| Invented API | fetchUsers() called with an argument that does not exist in the library docs | The method name sounds plausible, and the model uses it consistently |
| Imaginary import | from pipeline.tasks import run_etl where pipeline is not installed | The module name follows naming conventions the model has seen in training |
| Synthetic edge-case handling | A try-except that catches DatabaseTimeoutError — a class that does not exist in the driver | The error name follows a realistic pattern |
| Confident wrong logic | An optimisation that claims O(log n) performance but actually iterates every row | The algorithm description matches the right big-O for a different approach |
| Hallucinated configuration | A docker-compose.yml service name that no official image publishes | The image name is consistent with the naming pattern of real images |
The five-point review checklist
Read every AI-generated block against these five checks before you commit.
1. Verify every import and dependency
The model is likelier to hallucinate a library name than you think. Before you run any AI-generated code, check that every import resolves to a real package or built-in module.
# The AI generated this — does cachetools exist on PyPI?
from cachetools import LRUCache
# Quick check in your terminal:
# pip install cachetools
If an import does not exist on PyPI, npm, or your language’s package registry, the model most likely invented it. Replace it with a real alternative or implement the feature manually.
2. Cross-reference every API call
When the model writes something like response = client.query(embedding=vector, top_k=5), check the library documentation — not the model’s memory — for the actual parameter names.
I have code that calls client.query() with a parameter called top_k. I am using the Pinecone Python SDK version 4.1. Check whether top_k is a valid parameter for the query() method. If it is not, tell me the correct parameter name and show the fix.
Provide your answer as a yes-or-no with the evidence from the docs.
A prompt like this forces the model to reveal the source of its knowledge. If it cannot cite a specific version of the docs, treat the API call as suspect and verify it yourself.
3. Run the code path, not just the happy path
AI models train on code that mostly works — they are optimised for the common case. This means they skip error handling, miss edge cases, and assume inputs are well-formed.
| Test scenario | What the model usually writes | What it misses |
|---|---|---|
| Empty array | Process every element | IndexError or incorrect aggregate |
| Null input | Assume a value exists | NullPointerException |
| Network failure | Call the API once | No retry or backoff |
| Malformed input | Parse successfully | No validation or sanitisation |
| Concurrent access | Execute sequentially | Race conditions |
For each function the model writes, add a test for at least two of these scenarios. If the model did not handle them, you have caught a hallucination-by-omission — code that works under ideal conditions but fails everywhere else.
4. Check for invented error classes
Models frequently invent exception classes that sound realistic. A try-except block that catches DatabaseTimeoutError is almost certainly hallucinated unless you recognise it from the specific driver you are using.
The fix is to check the library’s exception hierarchy. Most well-documented libraries list their custom exceptions in a single page. If the class is not there, change the catch to a standard exception or handle the failure mode differently.
5. Trace the data flow end to end
The most subtle hallucinations happen in the middle layers of a pipeline. The model generates a transformation function that looks correct in isolation but silently drops rows, misaligns column indices, or assumes sorted data where none exists.
Trace the following data flow step by step and tell me where data could be lost or corrupted.
[Paste the relevant functions here]
For each risk you identify, suggest a guard (assertion, type check, or test) that would catch it during development.
This prompt treats the model as a code reviewer for its own output — a pattern that catches many hallucinations before they become bugs.
When the model invents an API
Here is a concrete example. A developer asked an AI assistant to write a script that batches API requests using concurrent.futures. The model produced this:
import asyncio
from aiohttp import ClientSession, ClientTimeout
async def fetch_all(urls, max_concurrent=5):
semaphore = asyncio.Semaphore(max_concurrent)
timeout = ClientTimeout(total=30)
async with ClientSession(timeout=timeout) as session:
tasks = [fetch_one(session, url, semaphore) for url in urls]
return await asyncio.gather(*tasks)
The code looks correct. It uses asyncio, aiohttp, a semaphore for concurrency control — everything a Python developer would expect. The hallucination is invisible: aiohttp’s ClientSession does not accept a timeout parameter at the session level in the version the developer had installed. The parameter belongs on individual requests.
The fix is small, but it illustrates the pattern: the model used the right vocabulary and idiom — except for one parameter that does not exist in the real library. Without the review checklist, this code fails with a cryptic TypeError.
For a deeper guide on structuring AI coding sessions, see Harness Engineering.
Build review into your workflow
Add these habits to your regular practice:
- Never trust a first draft. Treat the first output as a starting point, not a finished product.
- Review in layers. Check imports first, then API calls, then error handling, then data flow.
- Run tests before you commit. If the model did not write tests, write at least one. It is your second pair of eyes.
- Ask the model to review itself. Prompt it to check its own code for invented APIs, fake imports, and hallucinated error classes.
- Keep a hallucination log. Note which patterns your model tends to produce. Some invent npm packages; others invent CSS properties. Knowing the weak spots makes review faster.
Trust but verify
AI coding tools are transformative, but they are also probabilistic engines that optimise for plausible output, not correct output.
The five-point checklist — verify imports, cross-reference APIs, test edge cases, check error classes, trace data flow — turns review from vague anxiety into a repeatable process. Apply it to every generated block to catch the hallucinations that look real and ship with more confidence.
For the full review pipeline from prompt design to production deployment, see Vibe Coding Pro.
Further reading
More insights
All ArticlesA 90-Day Roadmap for Rolling Out Agentic Coding on Your Team
Roll out agentic coding without the chaos — a phased plan that gives your team standards, governance, and a rollout pace they can actually sustain.
Read articleContext Windows, Memory, and Why Your AI Keeps "Forgetting" the Project
Discover why your AI loses track of your project mid-session and how context windows, memory files, and smart prompting keep conversations on track.
Read articleCursor Rules, .cursorrules, and Project Context That Sticks
How a single .cursorrules file keeps your AI coding tool grounded in your project's stack, conventions, and preferences — session after session.
Read articleCursor vs Claude Code vs GitHub Copilot: A Practical Comparison for 2026
See how Cursor, Claude Code, and GitHub Copilot compare across real workflows — and which AI coding tool fits your team and project in 2026.
Read article